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>
24a76caf55SØrjan Eide #include <linux/slab.h>
25a76caf55SØrjan Eide #include <linux/pm_opp.h>
26a76caf55SØrjan Eide #include <linux/thermal.h>
27a76caf55SØrjan Eide 
28a76caf55SØrjan Eide static DEFINE_MUTEX(devfreq_lock);
29a76caf55SØrjan Eide static DEFINE_IDR(devfreq_idr);
30a76caf55SØrjan Eide 
31a76caf55SØrjan Eide /**
32a76caf55SØrjan Eide  * struct devfreq_cooling_device - Devfreq cooling device
33a76caf55SØrjan Eide  * @id:		unique integer value corresponding to each
34a76caf55SØrjan Eide  *		devfreq_cooling_device registered.
35a76caf55SØrjan Eide  * @cdev:	Pointer to associated thermal cooling device.
36a76caf55SØrjan Eide  * @devfreq:	Pointer to associated devfreq device.
37a76caf55SØrjan Eide  * @cooling_state:	Current cooling state.
38a76caf55SØrjan Eide  * @power_table:	Pointer to table with maximum power draw for each
39a76caf55SØrjan Eide  *			cooling state. State is the index into the table, and
40a76caf55SØrjan Eide  *			the power is in mW.
41a76caf55SØrjan Eide  * @freq_table:	Pointer to a table with the frequencies sorted in descending
42a76caf55SØrjan Eide  *		order.  You can index the table by cooling device state
43a76caf55SØrjan Eide  * @freq_table_size:	Size of the @freq_table and @power_table
44a76caf55SØrjan Eide  * @power_ops:	Pointer to devfreq_cooling_power, used to generate the
45a76caf55SØrjan Eide  *		@power_table.
46a76caf55SØrjan Eide  */
47a76caf55SØrjan Eide struct devfreq_cooling_device {
48a76caf55SØrjan Eide 	int id;
49a76caf55SØrjan Eide 	struct thermal_cooling_device *cdev;
50a76caf55SØrjan Eide 	struct devfreq *devfreq;
51a76caf55SØrjan Eide 	unsigned long cooling_state;
52a76caf55SØrjan Eide 	u32 *power_table;
53a76caf55SØrjan Eide 	u32 *freq_table;
54a76caf55SØrjan Eide 	size_t freq_table_size;
55a76caf55SØrjan Eide 	struct devfreq_cooling_power *power_ops;
56a76caf55SØrjan Eide };
57a76caf55SØrjan Eide 
58a76caf55SØrjan Eide /**
59a76caf55SØrjan Eide  * get_idr - function to get a unique id.
60a76caf55SØrjan Eide  * @idr: struct idr * handle used to create a id.
61a76caf55SØrjan Eide  * @id: int * value generated by this function.
62a76caf55SØrjan Eide  *
63a76caf55SØrjan Eide  * This function will populate @id with an unique
64a76caf55SØrjan Eide  * id, using the idr API.
65a76caf55SØrjan Eide  *
66a76caf55SØrjan Eide  * Return: 0 on success, an error code on failure.
67a76caf55SØrjan Eide  */
68a76caf55SØrjan Eide static int get_idr(struct idr *idr, int *id)
69a76caf55SØrjan Eide {
70a76caf55SØrjan Eide 	int ret;
71a76caf55SØrjan Eide 
72a76caf55SØrjan Eide 	mutex_lock(&devfreq_lock);
73a76caf55SØrjan Eide 	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
74a76caf55SØrjan Eide 	mutex_unlock(&devfreq_lock);
75a76caf55SØrjan Eide 	if (unlikely(ret < 0))
76a76caf55SØrjan Eide 		return ret;
77a76caf55SØrjan Eide 	*id = ret;
78a76caf55SØrjan Eide 
79a76caf55SØrjan Eide 	return 0;
80a76caf55SØrjan Eide }
81a76caf55SØrjan Eide 
82a76caf55SØrjan Eide /**
83a76caf55SØrjan Eide  * release_idr - function to free the unique id.
84a76caf55SØrjan Eide  * @idr: struct idr * handle used for creating the id.
85a76caf55SØrjan Eide  * @id: int value representing the unique id.
86a76caf55SØrjan Eide  */
87a76caf55SØrjan Eide static void release_idr(struct idr *idr, int id)
88a76caf55SØrjan Eide {
89a76caf55SØrjan Eide 	mutex_lock(&devfreq_lock);
90a76caf55SØrjan Eide 	idr_remove(idr, id);
91a76caf55SØrjan Eide 	mutex_unlock(&devfreq_lock);
92a76caf55SØrjan Eide }
93a76caf55SØrjan Eide 
94a76caf55SØrjan Eide /**
95a76caf55SØrjan Eide  * partition_enable_opps() - disable all opps above a given state
96a76caf55SØrjan Eide  * @dfc:	Pointer to devfreq we are operating on
97a76caf55SØrjan Eide  * @cdev_state:	cooling device state we're setting
98a76caf55SØrjan Eide  *
99a76caf55SØrjan Eide  * Go through the OPPs of the device, enabling all OPPs until
100a76caf55SØrjan Eide  * @cdev_state and disabling those frequencies above it.
101a76caf55SØrjan Eide  */
102a76caf55SØrjan Eide static int partition_enable_opps(struct devfreq_cooling_device *dfc,
103a76caf55SØrjan Eide 				 unsigned long cdev_state)
104a76caf55SØrjan Eide {
105a76caf55SØrjan Eide 	int i;
106a76caf55SØrjan Eide 	struct device *dev = dfc->devfreq->dev.parent;
107a76caf55SØrjan Eide 
108a76caf55SØrjan Eide 	for (i = 0; i < dfc->freq_table_size; i++) {
109a76caf55SØrjan Eide 		struct dev_pm_opp *opp;
110a76caf55SØrjan Eide 		int ret = 0;
111a76caf55SØrjan Eide 		unsigned int freq = dfc->freq_table[i];
112a76caf55SØrjan Eide 		bool want_enable = i >= cdev_state ? true : false;
113a76caf55SØrjan Eide 
114a76caf55SØrjan Eide 		rcu_read_lock();
115a76caf55SØrjan Eide 		opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
116a76caf55SØrjan Eide 		rcu_read_unlock();
117a76caf55SØrjan Eide 
118a76caf55SØrjan Eide 		if (PTR_ERR(opp) == -ERANGE)
119a76caf55SØrjan Eide 			continue;
120a76caf55SØrjan Eide 		else if (IS_ERR(opp))
121a76caf55SØrjan Eide 			return PTR_ERR(opp);
122a76caf55SØrjan Eide 
123a76caf55SØrjan Eide 		if (want_enable)
124a76caf55SØrjan Eide 			ret = dev_pm_opp_enable(dev, freq);
125a76caf55SØrjan Eide 		else
126a76caf55SØrjan Eide 			ret = dev_pm_opp_disable(dev, freq);
127a76caf55SØrjan Eide 
128a76caf55SØrjan Eide 		if (ret)
129a76caf55SØrjan Eide 			return ret;
130a76caf55SØrjan Eide 	}
131a76caf55SØrjan Eide 
132a76caf55SØrjan Eide 	return 0;
133a76caf55SØrjan Eide }
134a76caf55SØrjan Eide 
135a76caf55SØrjan Eide static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev,
136a76caf55SØrjan Eide 					 unsigned long *state)
137a76caf55SØrjan Eide {
138a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
139a76caf55SØrjan Eide 
140a76caf55SØrjan Eide 	*state = dfc->freq_table_size - 1;
141a76caf55SØrjan Eide 
142a76caf55SØrjan Eide 	return 0;
143a76caf55SØrjan Eide }
144a76caf55SØrjan Eide 
145a76caf55SØrjan Eide static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev,
146a76caf55SØrjan Eide 					 unsigned long *state)
147a76caf55SØrjan Eide {
148a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
149a76caf55SØrjan Eide 
150a76caf55SØrjan Eide 	*state = dfc->cooling_state;
151a76caf55SØrjan Eide 
152a76caf55SØrjan Eide 	return 0;
153a76caf55SØrjan Eide }
154a76caf55SØrjan Eide 
155a76caf55SØrjan Eide static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev,
156a76caf55SØrjan Eide 					 unsigned long state)
157a76caf55SØrjan Eide {
158a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
159a76caf55SØrjan Eide 	struct devfreq *df = dfc->devfreq;
160a76caf55SØrjan Eide 	struct device *dev = df->dev.parent;
161a76caf55SØrjan Eide 	int ret;
162a76caf55SØrjan Eide 
163a76caf55SØrjan Eide 	if (state == dfc->cooling_state)
164a76caf55SØrjan Eide 		return 0;
165a76caf55SØrjan Eide 
166a76caf55SØrjan Eide 	dev_dbg(dev, "Setting cooling state %lu\n", state);
167a76caf55SØrjan Eide 
168a76caf55SØrjan Eide 	if (state >= dfc->freq_table_size)
169a76caf55SØrjan Eide 		return -EINVAL;
170a76caf55SØrjan Eide 
171a76caf55SØrjan Eide 	ret = partition_enable_opps(dfc, state);
172a76caf55SØrjan Eide 	if (ret)
173a76caf55SØrjan Eide 		return ret;
174a76caf55SØrjan Eide 
175a76caf55SØrjan Eide 	dfc->cooling_state = state;
176a76caf55SØrjan Eide 
177a76caf55SØrjan Eide 	return 0;
178a76caf55SØrjan Eide }
179a76caf55SØrjan Eide 
180a76caf55SØrjan Eide /**
181a76caf55SØrjan Eide  * freq_get_state() - get the cooling state corresponding to a frequency
182a76caf55SØrjan Eide  * @dfc:	Pointer to devfreq cooling device
183a76caf55SØrjan Eide  * @freq:	frequency in Hz
184a76caf55SØrjan Eide  *
185a76caf55SØrjan Eide  * Return: the cooling state associated with the @freq, or
186a76caf55SØrjan Eide  * THERMAL_CSTATE_INVALID if it wasn't found.
187a76caf55SØrjan Eide  */
188a76caf55SØrjan Eide static unsigned long
189a76caf55SØrjan Eide freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq)
190a76caf55SØrjan Eide {
191a76caf55SØrjan Eide 	int i;
192a76caf55SØrjan Eide 
193a76caf55SØrjan Eide 	for (i = 0; i < dfc->freq_table_size; i++) {
194a76caf55SØrjan Eide 		if (dfc->freq_table[i] == freq)
195a76caf55SØrjan Eide 			return i;
196a76caf55SØrjan Eide 	}
197a76caf55SØrjan Eide 
198a76caf55SØrjan Eide 	return THERMAL_CSTATE_INVALID;
199a76caf55SØrjan Eide }
200a76caf55SØrjan Eide 
201a76caf55SØrjan Eide /**
202a76caf55SØrjan Eide  * get_static_power() - calculate the static power
203a76caf55SØrjan Eide  * @dfc:	Pointer to devfreq cooling device
204a76caf55SØrjan Eide  * @freq:	Frequency in Hz
205a76caf55SØrjan Eide  *
206a76caf55SØrjan Eide  * Calculate the static power in milliwatts using the supplied
207a76caf55SØrjan Eide  * get_static_power().  The current voltage is calculated using the
208a76caf55SØrjan Eide  * OPP library.  If no get_static_power() was supplied, assume the
209a76caf55SØrjan Eide  * static power is negligible.
210a76caf55SØrjan Eide  */
211a76caf55SØrjan Eide static unsigned long
212a76caf55SØrjan Eide get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
213a76caf55SØrjan Eide {
214a76caf55SØrjan Eide 	struct devfreq *df = dfc->devfreq;
215a76caf55SØrjan Eide 	struct device *dev = df->dev.parent;
216a76caf55SØrjan Eide 	unsigned long voltage;
217a76caf55SØrjan Eide 	struct dev_pm_opp *opp;
218a76caf55SØrjan Eide 
219a76caf55SØrjan Eide 	if (!dfc->power_ops->get_static_power)
220a76caf55SØrjan Eide 		return 0;
221a76caf55SØrjan Eide 
222a76caf55SØrjan Eide 	rcu_read_lock();
223a76caf55SØrjan Eide 
224a76caf55SØrjan Eide 	opp = dev_pm_opp_find_freq_exact(dev, freq, true);
225a76caf55SØrjan Eide 	if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
226a76caf55SØrjan Eide 		opp = dev_pm_opp_find_freq_exact(dev, freq, false);
227a76caf55SØrjan Eide 
228a76caf55SØrjan Eide 	voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
229a76caf55SØrjan Eide 
230a76caf55SØrjan Eide 	rcu_read_unlock();
231a76caf55SØrjan Eide 
232a76caf55SØrjan Eide 	if (voltage == 0) {
233a76caf55SØrjan Eide 		dev_warn_ratelimited(dev,
234a76caf55SØrjan Eide 				     "Failed to get voltage for frequency %lu: %ld\n",
235a76caf55SØrjan Eide 				     freq, IS_ERR(opp) ? PTR_ERR(opp) : 0);
236a76caf55SØrjan Eide 		return 0;
237a76caf55SØrjan Eide 	}
238a76caf55SØrjan Eide 
239a76caf55SØrjan Eide 	return dfc->power_ops->get_static_power(voltage);
240a76caf55SØrjan Eide }
241a76caf55SØrjan Eide 
242a76caf55SØrjan Eide /**
243a76caf55SØrjan Eide  * get_dynamic_power - calculate the dynamic power
244a76caf55SØrjan Eide  * @dfc:	Pointer to devfreq cooling device
245a76caf55SØrjan Eide  * @freq:	Frequency in Hz
246a76caf55SØrjan Eide  * @voltage:	Voltage in millivolts
247a76caf55SØrjan Eide  *
248a76caf55SØrjan Eide  * Calculate the dynamic power in milliwatts consumed by the device at
249a76caf55SØrjan Eide  * frequency @freq and voltage @voltage.  If the get_dynamic_power()
250a76caf55SØrjan Eide  * was supplied as part of the devfreq_cooling_power struct, then that
251a76caf55SØrjan Eide  * function is used.  Otherwise, a simple power model (Pdyn = Coeff *
252a76caf55SØrjan Eide  * Voltage^2 * Frequency) is used.
253a76caf55SØrjan Eide  */
254a76caf55SØrjan Eide static unsigned long
255a76caf55SØrjan Eide get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq,
256a76caf55SØrjan Eide 		  unsigned long voltage)
257a76caf55SØrjan Eide {
258a76caf55SØrjan Eide 	unsigned long power;
259a76caf55SØrjan Eide 	u32 freq_mhz;
260a76caf55SØrjan Eide 	struct devfreq_cooling_power *dfc_power = dfc->power_ops;
261a76caf55SØrjan Eide 
262a76caf55SØrjan Eide 	if (dfc_power->get_dynamic_power)
263a76caf55SØrjan Eide 		return dfc_power->get_dynamic_power(freq, voltage);
264a76caf55SØrjan Eide 
265a76caf55SØrjan Eide 	freq_mhz = freq / 1000000;
266a76caf55SØrjan Eide 	power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage;
267a76caf55SØrjan Eide 	do_div(power, 1000000000);
268a76caf55SØrjan Eide 
269a76caf55SØrjan Eide 	return power;
270a76caf55SØrjan Eide }
271a76caf55SØrjan Eide 
272a76caf55SØrjan Eide static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev,
273a76caf55SØrjan Eide 					       struct thermal_zone_device *tz,
274a76caf55SØrjan Eide 					       u32 *power)
275a76caf55SØrjan Eide {
276a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
277a76caf55SØrjan Eide 	struct devfreq *df = dfc->devfreq;
278a76caf55SØrjan Eide 	struct devfreq_dev_status *status = &df->last_status;
279a76caf55SØrjan Eide 	unsigned long state;
280a76caf55SØrjan Eide 	unsigned long freq = status->current_frequency;
281a76caf55SØrjan Eide 	u32 dyn_power, static_power;
282a76caf55SØrjan Eide 
283a76caf55SØrjan Eide 	/* Get dynamic power for state */
284a76caf55SØrjan Eide 	state = freq_get_state(dfc, freq);
285a76caf55SØrjan Eide 	if (state == THERMAL_CSTATE_INVALID)
286a76caf55SØrjan Eide 		return -EAGAIN;
287a76caf55SØrjan Eide 
288a76caf55SØrjan Eide 	dyn_power = dfc->power_table[state];
289a76caf55SØrjan Eide 
290a76caf55SØrjan Eide 	/* Scale dynamic power for utilization */
291a76caf55SØrjan Eide 	dyn_power = (dyn_power * status->busy_time) / status->total_time;
292a76caf55SØrjan Eide 
293a76caf55SØrjan Eide 	/* Get static power */
294a76caf55SØrjan Eide 	static_power = get_static_power(dfc, freq);
295a76caf55SØrjan Eide 
296a76caf55SØrjan Eide 	*power = dyn_power + static_power;
297a76caf55SØrjan Eide 
298a76caf55SØrjan Eide 	return 0;
299a76caf55SØrjan Eide }
300a76caf55SØrjan Eide 
301a76caf55SØrjan Eide static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev,
302a76caf55SØrjan Eide 				       struct thermal_zone_device *tz,
303a76caf55SØrjan Eide 				       unsigned long state,
304a76caf55SØrjan Eide 				       u32 *power)
305a76caf55SØrjan Eide {
306a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
307a76caf55SØrjan Eide 	unsigned long freq;
308a76caf55SØrjan Eide 	u32 static_power;
309a76caf55SØrjan Eide 
310a76caf55SØrjan Eide 	if (state < 0 || state >= dfc->freq_table_size)
311a76caf55SØrjan Eide 		return -EINVAL;
312a76caf55SØrjan Eide 
313a76caf55SØrjan Eide 	freq = dfc->freq_table[state];
314a76caf55SØrjan Eide 	static_power = get_static_power(dfc, freq);
315a76caf55SØrjan Eide 
316a76caf55SØrjan Eide 	*power = dfc->power_table[state] + static_power;
317a76caf55SØrjan Eide 	return 0;
318a76caf55SØrjan Eide }
319a76caf55SØrjan Eide 
320a76caf55SØrjan Eide static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
321a76caf55SØrjan Eide 				       struct thermal_zone_device *tz,
322a76caf55SØrjan Eide 				       u32 power, unsigned long *state)
323a76caf55SØrjan Eide {
324a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc = cdev->devdata;
325a76caf55SØrjan Eide 	struct devfreq *df = dfc->devfreq;
326a76caf55SØrjan Eide 	struct devfreq_dev_status *status = &df->last_status;
327a76caf55SØrjan Eide 	unsigned long freq = status->current_frequency;
328a76caf55SØrjan Eide 	unsigned long busy_time;
329a76caf55SØrjan Eide 	s32 dyn_power;
330a76caf55SØrjan Eide 	u32 static_power;
331a76caf55SØrjan Eide 	int i;
332a76caf55SØrjan Eide 
333a76caf55SØrjan Eide 	static_power = get_static_power(dfc, freq);
334a76caf55SØrjan Eide 
335a76caf55SØrjan Eide 	dyn_power = power - static_power;
336a76caf55SØrjan Eide 	dyn_power = dyn_power > 0 ? dyn_power : 0;
337a76caf55SØrjan Eide 
338a76caf55SØrjan Eide 	/* Scale dynamic power for utilization */
339a76caf55SØrjan Eide 	busy_time = status->busy_time ?: 1;
340a76caf55SØrjan Eide 	dyn_power = (dyn_power * status->total_time) / busy_time;
341a76caf55SØrjan Eide 
342a76caf55SØrjan Eide 	/*
343a76caf55SØrjan Eide 	 * Find the first cooling state that is within the power
344a76caf55SØrjan Eide 	 * budget for dynamic power.
345a76caf55SØrjan Eide 	 */
346a76caf55SØrjan Eide 	for (i = 0; i < dfc->freq_table_size - 1; i++)
347a76caf55SØrjan Eide 		if (dyn_power >= dfc->power_table[i])
348a76caf55SØrjan Eide 			break;
349a76caf55SØrjan Eide 
350a76caf55SØrjan Eide 	*state = i;
351a76caf55SØrjan Eide 	return 0;
352a76caf55SØrjan Eide }
353a76caf55SØrjan Eide 
354a76caf55SØrjan Eide static struct thermal_cooling_device_ops devfreq_cooling_ops = {
355a76caf55SØrjan Eide 	.get_max_state = devfreq_cooling_get_max_state,
356a76caf55SØrjan Eide 	.get_cur_state = devfreq_cooling_get_cur_state,
357a76caf55SØrjan Eide 	.set_cur_state = devfreq_cooling_set_cur_state,
358a76caf55SØrjan Eide };
359a76caf55SØrjan Eide 
360a76caf55SØrjan Eide /**
361a76caf55SØrjan Eide  * devfreq_cooling_gen_tables() - Generate power and freq tables.
362a76caf55SØrjan Eide  * @dfc: Pointer to devfreq cooling device.
363a76caf55SØrjan Eide  *
364a76caf55SØrjan Eide  * Generate power and frequency tables: the power table hold the
365a76caf55SØrjan Eide  * device's maximum power usage at each cooling state (OPP).  The
366a76caf55SØrjan Eide  * static and dynamic power using the appropriate voltage and
367a76caf55SØrjan Eide  * frequency for the state, is acquired from the struct
368a76caf55SØrjan Eide  * devfreq_cooling_power, and summed to make the maximum power draw.
369a76caf55SØrjan Eide  *
370a76caf55SØrjan Eide  * The frequency table holds the frequencies in descending order.
371a76caf55SØrjan Eide  * That way its indexed by cooling device state.
372a76caf55SØrjan Eide  *
373a76caf55SØrjan Eide  * The tables are malloced, and pointers put in dfc.  They must be
374a76caf55SØrjan Eide  * freed when unregistering the devfreq cooling device.
375a76caf55SØrjan Eide  *
376a76caf55SØrjan Eide  * Return: 0 on success, negative error code on failure.
377a76caf55SØrjan Eide  */
378a76caf55SØrjan Eide static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
379a76caf55SØrjan Eide {
380a76caf55SØrjan Eide 	struct devfreq *df = dfc->devfreq;
381a76caf55SØrjan Eide 	struct device *dev = df->dev.parent;
382a76caf55SØrjan Eide 	int ret, num_opps;
383a76caf55SØrjan Eide 	unsigned long freq;
384a76caf55SØrjan Eide 	u32 *power_table = NULL;
385a76caf55SØrjan Eide 	u32 *freq_table;
386a76caf55SØrjan Eide 	int i;
387a76caf55SØrjan Eide 
388a76caf55SØrjan Eide 	num_opps = dev_pm_opp_get_opp_count(dev);
389a76caf55SØrjan Eide 
390a76caf55SØrjan Eide 	if (dfc->power_ops) {
391a76caf55SØrjan Eide 		power_table = kcalloc(num_opps, sizeof(*power_table),
392a76caf55SØrjan Eide 				      GFP_KERNEL);
393a76caf55SØrjan Eide 		if (!power_table)
394a76caf55SØrjan Eide 			ret = -ENOMEM;
395a76caf55SØrjan Eide 	}
396a76caf55SØrjan Eide 
397a76caf55SØrjan Eide 	freq_table = kcalloc(num_opps, sizeof(*freq_table),
398a76caf55SØrjan Eide 			     GFP_KERNEL);
399a76caf55SØrjan Eide 	if (!freq_table) {
400a76caf55SØrjan Eide 		ret = -ENOMEM;
401a76caf55SØrjan Eide 		goto free_power_table;
402a76caf55SØrjan Eide 	}
403a76caf55SØrjan Eide 
404a76caf55SØrjan Eide 	for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) {
405a76caf55SØrjan Eide 		unsigned long power_dyn, voltage;
406a76caf55SØrjan Eide 		struct dev_pm_opp *opp;
407a76caf55SØrjan Eide 
408a76caf55SØrjan Eide 		rcu_read_lock();
409a76caf55SØrjan Eide 
410a76caf55SØrjan Eide 		opp = dev_pm_opp_find_freq_floor(dev, &freq);
411a76caf55SØrjan Eide 		if (IS_ERR(opp)) {
412a76caf55SØrjan Eide 			rcu_read_unlock();
413a76caf55SØrjan Eide 			ret = PTR_ERR(opp);
414a76caf55SØrjan Eide 			goto free_tables;
415a76caf55SØrjan Eide 		}
416a76caf55SØrjan Eide 
417a76caf55SØrjan Eide 		voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
418a76caf55SØrjan Eide 
419a76caf55SØrjan Eide 		rcu_read_unlock();
420a76caf55SØrjan Eide 
421a76caf55SØrjan Eide 		if (dfc->power_ops) {
422a76caf55SØrjan Eide 			power_dyn = get_dynamic_power(dfc, freq, voltage);
423a76caf55SØrjan Eide 
424a76caf55SØrjan Eide 			dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n",
425a76caf55SØrjan Eide 				freq / 1000000, voltage, power_dyn, power_dyn);
426a76caf55SØrjan Eide 
427a76caf55SØrjan Eide 			power_table[i] = power_dyn;
428a76caf55SØrjan Eide 		}
429a76caf55SØrjan Eide 
430a76caf55SØrjan Eide 		freq_table[i] = freq;
431a76caf55SØrjan Eide 	}
432a76caf55SØrjan Eide 
433a76caf55SØrjan Eide 	if (dfc->power_ops)
434a76caf55SØrjan Eide 		dfc->power_table = power_table;
435a76caf55SØrjan Eide 
436a76caf55SØrjan Eide 	dfc->freq_table = freq_table;
437a76caf55SØrjan Eide 	dfc->freq_table_size = num_opps;
438a76caf55SØrjan Eide 
439a76caf55SØrjan Eide 	return 0;
440a76caf55SØrjan Eide 
441a76caf55SØrjan Eide free_tables:
442a76caf55SØrjan Eide 	kfree(freq_table);
443a76caf55SØrjan Eide free_power_table:
444a76caf55SØrjan Eide 	kfree(power_table);
445a76caf55SØrjan Eide 
446a76caf55SØrjan Eide 	return ret;
447a76caf55SØrjan Eide }
448a76caf55SØrjan Eide 
449a76caf55SØrjan Eide /**
450a76caf55SØrjan Eide  * of_devfreq_cooling_register_power() - Register devfreq cooling device,
451a76caf55SØrjan Eide  *                                      with OF and power information.
452a76caf55SØrjan Eide  * @np:	Pointer to OF device_node.
453a76caf55SØrjan Eide  * @df:	Pointer to devfreq device.
454a76caf55SØrjan Eide  * @dfc_power:	Pointer to devfreq_cooling_power.
455a76caf55SØrjan Eide  *
456a76caf55SØrjan Eide  * Register a devfreq cooling device.  The available OPPs must be
457a76caf55SØrjan Eide  * registered on the device.
458a76caf55SØrjan Eide  *
459a76caf55SØrjan Eide  * If @dfc_power is provided, the cooling device is registered with the
460a76caf55SØrjan Eide  * power extensions.  For the power extensions to work correctly,
461a76caf55SØrjan Eide  * devfreq should use the simple_ondemand governor, other governors
462a76caf55SØrjan Eide  * are not currently supported.
463a76caf55SØrjan Eide  */
464a76caf55SØrjan Eide struct devfreq_cooling_device *
465a76caf55SØrjan Eide of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
466a76caf55SØrjan Eide 				  struct devfreq_cooling_power *dfc_power)
467a76caf55SØrjan Eide {
468a76caf55SØrjan Eide 	struct thermal_cooling_device *cdev;
469a76caf55SØrjan Eide 	struct devfreq_cooling_device *dfc;
470a76caf55SØrjan Eide 	char dev_name[THERMAL_NAME_LENGTH];
471a76caf55SØrjan Eide 	int err;
472a76caf55SØrjan Eide 
473a76caf55SØrjan Eide 	dfc = kzalloc(sizeof(*dfc), GFP_KERNEL);
474a76caf55SØrjan Eide 	if (!dfc)
475a76caf55SØrjan Eide 		return ERR_PTR(-ENOMEM);
476a76caf55SØrjan Eide 
477a76caf55SØrjan Eide 	dfc->devfreq = df;
478a76caf55SØrjan Eide 
479a76caf55SØrjan Eide 	if (dfc_power) {
480a76caf55SØrjan Eide 		dfc->power_ops = dfc_power;
481a76caf55SØrjan Eide 
482a76caf55SØrjan Eide 		devfreq_cooling_ops.get_requested_power =
483a76caf55SØrjan Eide 			devfreq_cooling_get_requested_power;
484a76caf55SØrjan Eide 		devfreq_cooling_ops.state2power = devfreq_cooling_state2power;
485a76caf55SØrjan Eide 		devfreq_cooling_ops.power2state = devfreq_cooling_power2state;
486a76caf55SØrjan Eide 	}
487a76caf55SØrjan Eide 
488a76caf55SØrjan Eide 	err = devfreq_cooling_gen_tables(dfc);
489a76caf55SØrjan Eide 	if (err)
490a76caf55SØrjan Eide 		goto free_dfc;
491a76caf55SØrjan Eide 
492a76caf55SØrjan Eide 	err = get_idr(&devfreq_idr, &dfc->id);
493a76caf55SØrjan Eide 	if (err)
494a76caf55SØrjan Eide 		goto free_tables;
495a76caf55SØrjan Eide 
496a76caf55SØrjan Eide 	snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
497a76caf55SØrjan Eide 
498a76caf55SØrjan Eide 	cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
499a76caf55SØrjan Eide 						  &devfreq_cooling_ops);
500a76caf55SØrjan Eide 	if (IS_ERR(cdev)) {
501a76caf55SØrjan Eide 		err = PTR_ERR(cdev);
502a76caf55SØrjan Eide 		dev_err(df->dev.parent,
503a76caf55SØrjan Eide 			"Failed to register devfreq cooling device (%d)\n",
504a76caf55SØrjan Eide 			err);
505a76caf55SØrjan Eide 		goto release_idr;
506a76caf55SØrjan Eide 	}
507a76caf55SØrjan Eide 
508a76caf55SØrjan Eide 	dfc->cdev = cdev;
509a76caf55SØrjan Eide 
510a76caf55SØrjan Eide 	return dfc;
511a76caf55SØrjan Eide 
512a76caf55SØrjan Eide release_idr:
513a76caf55SØrjan Eide 	release_idr(&devfreq_idr, dfc->id);
514a76caf55SØrjan Eide free_tables:
515a76caf55SØrjan Eide 	kfree(dfc->power_table);
516a76caf55SØrjan Eide 	kfree(dfc->freq_table);
517a76caf55SØrjan Eide free_dfc:
518a76caf55SØrjan Eide 	kfree(dfc);
519a76caf55SØrjan Eide 
520a76caf55SØrjan Eide 	return ERR_PTR(err);
521a76caf55SØrjan Eide }
522a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power);
523a76caf55SØrjan Eide 
524a76caf55SØrjan Eide /**
525a76caf55SØrjan Eide  * of_devfreq_cooling_register() - Register devfreq cooling device,
526a76caf55SØrjan Eide  *                                with OF information.
527a76caf55SØrjan Eide  * @np: Pointer to OF device_node.
528a76caf55SØrjan Eide  * @df: Pointer to devfreq device.
529a76caf55SØrjan Eide  */
530a76caf55SØrjan Eide struct devfreq_cooling_device *
531a76caf55SØrjan Eide of_devfreq_cooling_register(struct device_node *np, struct devfreq *df)
532a76caf55SØrjan Eide {
533a76caf55SØrjan Eide 	return of_devfreq_cooling_register_power(np, df, NULL);
534a76caf55SØrjan Eide }
535a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(of_devfreq_cooling_register);
536a76caf55SØrjan Eide 
537a76caf55SØrjan Eide /**
538a76caf55SØrjan Eide  * devfreq_cooling_register() - Register devfreq cooling device.
539a76caf55SØrjan Eide  * @df: Pointer to devfreq device.
540a76caf55SØrjan Eide  */
541a76caf55SØrjan Eide struct devfreq_cooling_device *devfreq_cooling_register(struct devfreq *df)
542a76caf55SØrjan Eide {
543a76caf55SØrjan Eide 	return of_devfreq_cooling_register(NULL, df);
544a76caf55SØrjan Eide }
545a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_register);
546a76caf55SØrjan Eide 
547a76caf55SØrjan Eide /**
548a76caf55SØrjan Eide  * devfreq_cooling_unregister() - Unregister devfreq cooling device.
549a76caf55SØrjan Eide  * @dfc: Pointer to devfreq cooling device to unregister.
550a76caf55SØrjan Eide  */
551a76caf55SØrjan Eide void devfreq_cooling_unregister(struct devfreq_cooling_device *dfc)
552a76caf55SØrjan Eide {
553a76caf55SØrjan Eide 	if (!dfc)
554a76caf55SØrjan Eide 		return;
555a76caf55SØrjan Eide 
556a76caf55SØrjan Eide 	thermal_cooling_device_unregister(dfc->cdev);
557a76caf55SØrjan Eide 	release_idr(&devfreq_idr, dfc->id);
558a76caf55SØrjan Eide 	kfree(dfc->power_table);
559a76caf55SØrjan Eide 	kfree(dfc->freq_table);
560a76caf55SØrjan Eide 
561a76caf55SØrjan Eide 	kfree(dfc);
562a76caf55SØrjan Eide }
563a76caf55SØrjan Eide EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
564