Blame view

drivers/opp/core.c 63.8 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
e1f60b292   Nishanth Menon   PM: Introduce lib...
2
3
4
5
6
7
8
  /*
   * Generic OPP Interface
   *
   * Copyright (C) 2009-2010 Texas Instruments Incorporated.
   *	Nishanth Menon
   *	Romit Dasgupta
   *	Kevin Hilman
e1f60b292   Nishanth Menon   PM: Introduce lib...
9
   */
d6d2a5289   Viresh Kumar   PM / OPP: Improve...
10
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
d54974c25   Viresh Kumar   PM / OPP: Manage ...
11
  #include <linux/clk.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
12
13
  #include <linux/errno.h>
  #include <linux/err.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
14
  #include <linux/slab.h>
51990e825   Paul Gortmaker   device.h: cleanup...
15
  #include <linux/device.h>
80126ce7a   Liam Girdwood   PM / OPP: Export ...
16
  #include <linux/export.h>
009acd196   Viresh Kumar   PM / OPP: Support...
17
  #include <linux/pm_domain.h>
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
18
  #include <linux/regulator/consumer.h>
e1f60b292   Nishanth Menon   PM: Introduce lib...
19

f59d3ee84   Viresh Kumar   PM / OPP: Move cp...
20
  #include "opp.h"
e1f60b292   Nishanth Menon   PM: Introduce lib...
21
22
  
  /*
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
23
24
   * The root of the list of all opp-tables. All opp_table structures branch off
   * from here, with each opp_table containing the list of opps it supports in
e1f60b292   Nishanth Menon   PM: Introduce lib...
25
26
   * various states of availability.
   */
f47b72a15   Viresh Kumar   PM / OPP: Move CO...
27
  LIST_HEAD(opp_tables);
e1f60b292   Nishanth Menon   PM: Introduce lib...
28
  /* Lock to allow exclusive modification to the device and opp lists */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
29
  DEFINE_MUTEX(opp_table_lock);
e1f60b292   Nishanth Menon   PM: Introduce lib...
30

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
31
32
  static struct opp_device *_find_opp_dev(const struct device *dev,
  					struct opp_table *opp_table)
064416586   Viresh Kumar   PM / OPP: Add OPP...
33
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
34
  	struct opp_device *opp_dev;
064416586   Viresh Kumar   PM / OPP: Add OPP...
35

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
36
37
38
  	list_for_each_entry(opp_dev, &opp_table->dev_list, node)
  		if (opp_dev->dev == dev)
  			return opp_dev;
064416586   Viresh Kumar   PM / OPP: Add OPP...
39
40
41
  
  	return NULL;
  }
6ac423973   Wei Yongjun   PM / OPP: Make _f...
42
  static struct opp_table *_find_opp_table_unlocked(struct device *dev)
5b650b388   Viresh Kumar   PM / OPP: Take kr...
43
44
  {
  	struct opp_table *opp_table;
3d2556992   Viresh Kumar   OPP: Protect dev_...
45
  	bool found;
5b650b388   Viresh Kumar   PM / OPP: Take kr...
46
47
  
  	list_for_each_entry(opp_table, &opp_tables, node) {
3d2556992   Viresh Kumar   OPP: Protect dev_...
48
49
50
51
52
  		mutex_lock(&opp_table->lock);
  		found = !!_find_opp_dev(dev, opp_table);
  		mutex_unlock(&opp_table->lock);
  
  		if (found) {
5b650b388   Viresh Kumar   PM / OPP: Take kr...
53
54
55
56
57
58
59
60
  			_get_opp_table_kref(opp_table);
  
  			return opp_table;
  		}
  	}
  
  	return ERR_PTR(-ENODEV);
  }
e1f60b292   Nishanth Menon   PM: Introduce lib...
61
  /**
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
62
63
   * _find_opp_table() - find opp_table struct using device pointer
   * @dev:	device pointer used to lookup OPP table
e1f60b292   Nishanth Menon   PM: Introduce lib...
64
   *
052c6f191   Viresh Kumar   PM / OPP: Move aw...
65
   * Search OPP table for one containing matching device.
e1f60b292   Nishanth Menon   PM: Introduce lib...
66
   *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
67
   * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
e1f60b292   Nishanth Menon   PM: Introduce lib...
68
69
   * -EINVAL based on type of error.
   *
5b650b388   Viresh Kumar   PM / OPP: Take kr...
70
   * The callers must call dev_pm_opp_put_opp_table() after the table is used.
e1f60b292   Nishanth Menon   PM: Introduce lib...
71
   */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
72
  struct opp_table *_find_opp_table(struct device *dev)
e1f60b292   Nishanth Menon   PM: Introduce lib...
73
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
74
  	struct opp_table *opp_table;
e1f60b292   Nishanth Menon   PM: Introduce lib...
75

50a3cb04a   Viresh Kumar   PM / OPP: Drop un...
76
  	if (IS_ERR_OR_NULL(dev)) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
77
78
79
80
  		pr_err("%s: Invalid parameters
  ", __func__);
  		return ERR_PTR(-EINVAL);
  	}
5b650b388   Viresh Kumar   PM / OPP: Take kr...
81
82
83
  	mutex_lock(&opp_table_lock);
  	opp_table = _find_opp_table_unlocked(dev);
  	mutex_unlock(&opp_table_lock);
e1f60b292   Nishanth Menon   PM: Introduce lib...
84

5b650b388   Viresh Kumar   PM / OPP: Take kr...
85
  	return opp_table;
e1f60b292   Nishanth Menon   PM: Introduce lib...
86
87
88
  }
  
  /**
d6d007429   Javi Merino   PM / OPP: get the...
89
   * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
90
91
   * @opp:	opp for which voltage has to be returned for
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
92
   * Return: voltage in micro volt corresponding to the opp, else
e1f60b292   Nishanth Menon   PM: Introduce lib...
93
94
   * return 0
   *
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
95
   * This is useful only for devices with single power supply.
e1f60b292   Nishanth Menon   PM: Introduce lib...
96
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
97
  unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
e1f60b292   Nishanth Menon   PM: Introduce lib...
98
  {
052c6f191   Viresh Kumar   PM / OPP: Move aw...
99
  	if (IS_ERR_OR_NULL(opp)) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
100
101
  		pr_err("%s: Invalid parameters
  ", __func__);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
102
103
  		return 0;
  	}
e1f60b292   Nishanth Menon   PM: Introduce lib...
104

052c6f191   Viresh Kumar   PM / OPP: Move aw...
105
  	return opp->supplies[0].u_volt;
e1f60b292   Nishanth Menon   PM: Introduce lib...
106
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
107
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
e1f60b292   Nishanth Menon   PM: Introduce lib...
108
109
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
110
   * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
111
112
   * @opp:	opp for which frequency has to be returned for
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
113
   * Return: frequency in hertz corresponding to the opp, else
e1f60b292   Nishanth Menon   PM: Introduce lib...
114
   * return 0
e1f60b292   Nishanth Menon   PM: Introduce lib...
115
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
116
  unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
e1f60b292   Nishanth Menon   PM: Introduce lib...
117
  {
06a8a059e   Andrew-sh.Cheng   opp: Allow disabl...
118
  	if (IS_ERR_OR_NULL(opp)) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
119
120
  		pr_err("%s: Invalid parameters
  ", __func__);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
121
122
  		return 0;
  	}
e1f60b292   Nishanth Menon   PM: Introduce lib...
123

052c6f191   Viresh Kumar   PM / OPP: Move aw...
124
  	return opp->rate;
e1f60b292   Nishanth Menon   PM: Introduce lib...
125
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
126
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
e1f60b292   Nishanth Menon   PM: Introduce lib...
127
128
  
  /**
5b93ac542   Rajendra Nayak   OPP: Add support ...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
   * dev_pm_opp_get_level() - Gets the level corresponding to an available opp
   * @opp:	opp for which level value has to be returned for
   *
   * Return: level read from device tree corresponding to the opp, else
   * return 0.
   */
  unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)
  {
  	if (IS_ERR_OR_NULL(opp) || !opp->available) {
  		pr_err("%s: Invalid parameters
  ", __func__);
  		return 0;
  	}
  
  	return opp->level;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_level);
  
  /**
19445b25e   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
148
149
150
151
152
153
154
155
   * dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not
   * @opp: opp for which turbo mode is being verified
   *
   * Turbo OPPs are not for normal use, and can be enabled (under certain
   * conditions) for short duration of times to finish high throughput work
   * quickly. Running on them for longer times may overheat the chip.
   *
   * Return: true if opp is turbo opp, else false.
19445b25e   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
156
157
158
   */
  bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp)
  {
052c6f191   Viresh Kumar   PM / OPP: Move aw...
159
  	if (IS_ERR_OR_NULL(opp) || !opp->available) {
19445b25e   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
160
161
162
163
  		pr_err("%s: Invalid parameters
  ", __func__);
  		return false;
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
164
  	return opp->turbo;
19445b25e   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
165
166
167
168
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
  
  /**
3ca9bb33c   Viresh Kumar   PM / OPP: Add clo...
169
170
171
172
   * dev_pm_opp_get_max_clock_latency() - Get max clock latency in nanoseconds
   * @dev:	device for which we do this operation
   *
   * Return: This function returns the max clock latency in nanoseconds.
3ca9bb33c   Viresh Kumar   PM / OPP: Add clo...
173
174
175
   */
  unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
176
  	struct opp_table *opp_table;
3ca9bb33c   Viresh Kumar   PM / OPP: Add clo...
177
  	unsigned long clock_latency_ns;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
178
179
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table))
5b650b388   Viresh Kumar   PM / OPP: Take kr...
180
181
182
183
184
  		return 0;
  
  	clock_latency_ns = opp_table->clock_latency_ns_max;
  
  	dev_pm_opp_put_opp_table(opp_table);
3ca9bb33c   Viresh Kumar   PM / OPP: Add clo...
185

3ca9bb33c   Viresh Kumar   PM / OPP: Add clo...
186
187
188
189
190
  	return clock_latency_ns;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
  
  /**
655c9df96   Viresh Kumar   PM / OPP: Introdu...
191
192
193
194
   * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
   * @dev: device for which we do this operation
   *
   * Return: This function returns the max voltage latency in nanoseconds.
655c9df96   Viresh Kumar   PM / OPP: Introdu...
195
196
197
   */
  unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
198
  	struct opp_table *opp_table;
655c9df96   Viresh Kumar   PM / OPP: Introdu...
199
  	struct dev_pm_opp *opp;
478256bdd   Viresh Kumar   PM / OPP: Don't c...
200
  	struct regulator *reg;
655c9df96   Viresh Kumar   PM / OPP: Introdu...
201
  	unsigned long latency_ns = 0;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
202
203
204
205
206
  	int ret, i, count;
  	struct {
  		unsigned long min;
  		unsigned long max;
  	} *uV;
cdd3e614c   Viresh Kumar   PM / OPP: Simplif...
207
208
209
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table))
  		return 0;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
210
  	/* Regulator may not be required for the device */
90e3577b5   Viresh Kumar   OPP: Use opp_tabl...
211
  	if (!opp_table->regulators)
cdd3e614c   Viresh Kumar   PM / OPP: Simplif...
212
  		goto put_opp_table;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
213

90e3577b5   Viresh Kumar   OPP: Use opp_tabl...
214
  	count = opp_table->regulator_count;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
215
216
  	uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
  	if (!uV)
478256bdd   Viresh Kumar   PM / OPP: Don't c...
217
  		goto put_opp_table;
655c9df96   Viresh Kumar   PM / OPP: Introdu...
218

052c6f191   Viresh Kumar   PM / OPP: Move aw...
219
  	mutex_lock(&opp_table->lock);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
220
221
222
  	for (i = 0; i < count; i++) {
  		uV[i].min = ~0;
  		uV[i].max = 0;
655c9df96   Viresh Kumar   PM / OPP: Introdu...
223

052c6f191   Viresh Kumar   PM / OPP: Move aw...
224
  		list_for_each_entry(opp, &opp_table->opp_list, node) {
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
225
226
227
228
229
230
231
232
  			if (!opp->available)
  				continue;
  
  			if (opp->supplies[i].u_volt_min < uV[i].min)
  				uV[i].min = opp->supplies[i].u_volt_min;
  			if (opp->supplies[i].u_volt_max > uV[i].max)
  				uV[i].max = opp->supplies[i].u_volt_max;
  		}
655c9df96   Viresh Kumar   PM / OPP: Introdu...
233
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
234
  	mutex_unlock(&opp_table->lock);
655c9df96   Viresh Kumar   PM / OPP: Introdu...
235
236
  
  	/*
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
237
  	 * The caller needs to ensure that opp_table (and hence the regulator)
655c9df96   Viresh Kumar   PM / OPP: Introdu...
238
239
  	 * isn't freed, while we are executing this routine.
  	 */
8cc311167   Andrzej Hajda   PM / OPP: fix off...
240
  	for (i = 0; i < count; i++) {
478256bdd   Viresh Kumar   PM / OPP: Don't c...
241
  		reg = opp_table->regulators[i];
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
242
243
244
245
  		ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
  		if (ret > 0)
  			latency_ns += ret * 1000;
  	}
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
246
  	kfree(uV);
cdd3e614c   Viresh Kumar   PM / OPP: Simplif...
247
248
  put_opp_table:
  	dev_pm_opp_put_opp_table(opp_table);
655c9df96   Viresh Kumar   PM / OPP: Introdu...
249
250
251
252
253
254
  
  	return latency_ns;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency);
  
  /**
217434476   Viresh Kumar   PM / OPP: Introdu...
255
256
257
258
259
260
   * dev_pm_opp_get_max_transition_latency() - Get max transition latency in
   *					     nanoseconds
   * @dev: device for which we do this operation
   *
   * Return: This function returns the max transition latency, in nanoseconds, to
   * switch from one OPP to other.
217434476   Viresh Kumar   PM / OPP: Introdu...
261
262
263
264
265
266
267
268
269
   */
  unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
  {
  	return dev_pm_opp_get_max_volt_latency(dev) +
  		dev_pm_opp_get_max_clock_latency(dev);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency);
  
  /**
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
270
   * dev_pm_opp_get_suspend_opp_freq() - Get frequency of suspend opp in Hz
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
271
272
   * @dev:	device for which we do this operation
   *
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
273
274
   * Return: This function returns the frequency of the OPP marked as suspend_opp
   * if one is available, else returns 0;
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
275
   */
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
276
  unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
277
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
278
  	struct opp_table *opp_table;
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
279
  	unsigned long freq = 0;
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
280

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
281
  	opp_table = _find_opp_table(dev);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
282
283
  	if (IS_ERR(opp_table))
  		return 0;
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
284

5b650b388   Viresh Kumar   PM / OPP: Take kr...
285
286
287
288
  	if (opp_table->suspend_opp && opp_table->suspend_opp->available)
  		freq = dev_pm_opp_get_freq(opp_table->suspend_opp);
  
  	dev_pm_opp_put_opp_table(opp_table);
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
289

3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
290
  	return freq;
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
291
  }
3aa26a3b2   Viresh Kumar   PM / OPP: Rename ...
292
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
293

a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  int _get_opp_count(struct opp_table *opp_table)
  {
  	struct dev_pm_opp *opp;
  	int count = 0;
  
  	mutex_lock(&opp_table->lock);
  
  	list_for_each_entry(opp, &opp_table->opp_list, node) {
  		if (opp->available)
  			count++;
  	}
  
  	mutex_unlock(&opp_table->lock);
  
  	return count;
  }
4eafbd15b   Bartlomiej Zolnierkiewicz   PM / OPP: add dev...
310
  /**
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
311
   * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
e1f60b292   Nishanth Menon   PM: Introduce lib...
312
313
   * @dev:	device for which we do this operation
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
314
   * Return: This function returns the number of available opps if there are any,
e1f60b292   Nishanth Menon   PM: Introduce lib...
315
   * else returns 0 if none or the corresponding error value.
e1f60b292   Nishanth Menon   PM: Introduce lib...
316
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
317
  int dev_pm_opp_get_opp_count(struct device *dev)
e1f60b292   Nishanth Menon   PM: Introduce lib...
318
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
319
  	struct opp_table *opp_table;
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
320
  	int count;
e1f60b292   Nishanth Menon   PM: Introduce lib...
321

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
322
323
324
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		count = PTR_ERR(opp_table);
035ed0720   Fabio Estevam   PM / OPP: Move er...
325
326
  		dev_dbg(dev, "%s: OPP table not found (%d)
  ",
b4718c02f   Dmitry Torokhov   PM / OPP: take RC...
327
  			__func__, count);
09f662f95   Viresh Kumar   OPP: Return error...
328
  		return count;
e1f60b292   Nishanth Menon   PM: Introduce lib...
329
  	}
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
330
  	count = _get_opp_count(opp_table);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
331
  	dev_pm_opp_put_opp_table(opp_table);
e1f60b292   Nishanth Menon   PM: Introduce lib...
332
333
  	return count;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
334
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
e1f60b292   Nishanth Menon   PM: Introduce lib...
335
336
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
337
   * dev_pm_opp_find_freq_exact() - search for an exact frequency
e1f60b292   Nishanth Menon   PM: Introduce lib...
338
339
   * @dev:		device for which we do this operation
   * @freq:		frequency to search for
7ae496187   Nishanth Menon   PM / OPP: opp_fin...
340
   * @available:		true/false - match for available opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
341
   *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
342
   * Return: Searches for exact match in the opp table and returns pointer to the
984f16c84   Nishanth Menon   PM / OPP: Update ...
343
344
   * matching opp if found, else returns ERR_PTR in case of error and should
   * be handled using IS_ERR. Error return values can be:
0779726cc   Nishanth Menon   PM / OPP: predict...
345
346
347
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
348
349
350
351
352
353
354
355
   *
   * Note: available is a modifier for the search. if available=true, then the
   * match is for exact matching frequency and is available in the stored OPP
   * table. if false, the match is for exact frequency which is not available.
   *
   * This provides a mechanism to enable an opp which is not available currently
   * or the opposite as well.
   *
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
356
357
   * The callers are required to call dev_pm_opp_put() for the returned OPP after
   * use.
e1f60b292   Nishanth Menon   PM: Introduce lib...
358
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
359
360
361
  struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
  					      unsigned long freq,
  					      bool available)
e1f60b292   Nishanth Menon   PM: Introduce lib...
362
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
363
  	struct opp_table *opp_table;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
364
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
e1f60b292   Nishanth Menon   PM: Introduce lib...
365

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
366
367
368
369
370
371
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		int r = PTR_ERR(opp_table);
  
  		dev_err(dev, "%s: OPP table not found (%d)
  ", __func__, r);
e1f60b292   Nishanth Menon   PM: Introduce lib...
372
373
  		return ERR_PTR(r);
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
374
  	mutex_lock(&opp_table->lock);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
375

052c6f191   Viresh Kumar   PM / OPP: Move aw...
376
  	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
377
378
379
  		if (temp_opp->available == available &&
  				temp_opp->rate == freq) {
  			opp = temp_opp;
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
380
381
382
  
  			/* Increment the reference count of OPP */
  			dev_pm_opp_get(opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
383
384
385
  			break;
  		}
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
386
  	mutex_unlock(&opp_table->lock);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
387
  	dev_pm_opp_put_opp_table(opp_table);
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
388

e1f60b292   Nishanth Menon   PM: Introduce lib...
389
390
  	return opp;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
391
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
e1f60b292   Nishanth Menon   PM: Introduce lib...
392

71419d84c   Niklas Cassel   opp: Add dev_pm_o...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  /**
   * dev_pm_opp_find_level_exact() - search for an exact level
   * @dev:		device for which we do this operation
   * @level:		level to search for
   *
   * Return: Searches for exact match in the opp table and returns pointer to the
   * matching opp if found, else returns ERR_PTR in case of error and should
   * be handled using IS_ERR. Error return values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
   *
   * The callers are required to call dev_pm_opp_put() for the returned OPP after
   * use.
   */
  struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
  					       unsigned int level)
  {
  	struct opp_table *opp_table;
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
  
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		int r = PTR_ERR(opp_table);
  
  		dev_err(dev, "%s: OPP table not found (%d)
  ", __func__, r);
  		return ERR_PTR(r);
  	}
  
  	mutex_lock(&opp_table->lock);
  
  	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
  		if (temp_opp->level == level) {
  			opp = temp_opp;
  
  			/* Increment the reference count of OPP */
  			dev_pm_opp_get(opp);
  			break;
  		}
  	}
  
  	mutex_unlock(&opp_table->lock);
  	dev_pm_opp_put_opp_table(opp_table);
  
  	return opp;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
067b7ce08   Jisheng Zhang   PM / OPP: optimiz...
441
442
443
444
  static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
  						   unsigned long *freq)
  {
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
445
446
447
  	mutex_lock(&opp_table->lock);
  
  	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
067b7ce08   Jisheng Zhang   PM / OPP: optimiz...
448
449
450
  		if (temp_opp->available && temp_opp->rate >= *freq) {
  			opp = temp_opp;
  			*freq = opp->rate;
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
451
452
453
  
  			/* Increment the reference count of OPP */
  			dev_pm_opp_get(opp);
067b7ce08   Jisheng Zhang   PM / OPP: optimiz...
454
455
456
  			break;
  		}
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
457
  	mutex_unlock(&opp_table->lock);
067b7ce08   Jisheng Zhang   PM / OPP: optimiz...
458
459
  	return opp;
  }
e1f60b292   Nishanth Menon   PM: Introduce lib...
460
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
461
   * dev_pm_opp_find_freq_ceil() - Search for an rounded ceil freq
e1f60b292   Nishanth Menon   PM: Introduce lib...
462
463
464
465
466
467
   * @dev:	device for which we do this operation
   * @freq:	Start frequency
   *
   * Search for the matching ceil *available* OPP from a starting freq
   * for a device.
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
468
   * Return: matching *opp and refreshes *freq accordingly, else returns
0779726cc   Nishanth Menon   PM / OPP: predict...
469
470
471
472
473
   * ERR_PTR in case of error and should be handled using IS_ERR. Error return
   * values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
474
   *
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
475
476
   * The callers are required to call dev_pm_opp_put() for the returned OPP after
   * use.
e1f60b292   Nishanth Menon   PM: Introduce lib...
477
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
478
479
  struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
  					     unsigned long *freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
480
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
481
  	struct opp_table *opp_table;
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
482
  	struct dev_pm_opp *opp;
b02ded246   Dmitry Torokhov   PM / OPP: add som...
483

e1f60b292   Nishanth Menon   PM: Introduce lib...
484
485
486
487
488
  	if (!dev || !freq) {
  		dev_err(dev, "%s: Invalid argument freq=%p
  ", __func__, freq);
  		return ERR_PTR(-EINVAL);
  	}
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
489
  	opp_table = _find_opp_table(dev);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
490
  	if (IS_ERR(opp_table))
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
491
  		return ERR_CAST(opp_table);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
492

8a31d9d94   Viresh Kumar   PM / OPP: Update ...
493
  	opp = _find_freq_ceil(opp_table, freq);
e1f60b292   Nishanth Menon   PM: Introduce lib...
494

5b650b388   Viresh Kumar   PM / OPP: Take kr...
495
  	dev_pm_opp_put_opp_table(opp_table);
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
496
497
  
  	return opp;
e1f60b292   Nishanth Menon   PM: Introduce lib...
498
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
499
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
e1f60b292   Nishanth Menon   PM: Introduce lib...
500
501
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
502
   * dev_pm_opp_find_freq_floor() - Search for a rounded floor freq
e1f60b292   Nishanth Menon   PM: Introduce lib...
503
504
505
506
507
508
   * @dev:	device for which we do this operation
   * @freq:	Start frequency
   *
   * Search for the matching floor *available* OPP from a starting freq
   * for a device.
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
509
   * Return: matching *opp and refreshes *freq accordingly, else returns
0779726cc   Nishanth Menon   PM / OPP: predict...
510
511
512
513
514
   * ERR_PTR in case of error and should be handled using IS_ERR. Error return
   * values can be:
   * EINVAL:	for bad pointer
   * ERANGE:	no match found for search
   * ENODEV:	if device not found in list of registered devices
e1f60b292   Nishanth Menon   PM: Introduce lib...
515
   *
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
516
517
   * The callers are required to call dev_pm_opp_put() for the returned OPP after
   * use.
e1f60b292   Nishanth Menon   PM: Introduce lib...
518
   */
47d43ba73   Nishanth Menon   PM / OPP: rename ...
519
520
  struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
  					      unsigned long *freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
521
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
522
  	struct opp_table *opp_table;
47d43ba73   Nishanth Menon   PM / OPP: rename ...
523
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
e1f60b292   Nishanth Menon   PM: Introduce lib...
524
525
526
527
528
529
  
  	if (!dev || !freq) {
  		dev_err(dev, "%s: Invalid argument freq=%p
  ", __func__, freq);
  		return ERR_PTR(-EINVAL);
  	}
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
530
  	opp_table = _find_opp_table(dev);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
531
  	if (IS_ERR(opp_table))
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
532
  		return ERR_CAST(opp_table);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
533

052c6f191   Viresh Kumar   PM / OPP: Move aw...
534
  	mutex_lock(&opp_table->lock);
e1f60b292   Nishanth Menon   PM: Introduce lib...
535

052c6f191   Viresh Kumar   PM / OPP: Move aw...
536
  	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
537
538
539
540
541
542
543
544
  		if (temp_opp->available) {
  			/* go to the next node, before choosing prev */
  			if (temp_opp->rate > *freq)
  				break;
  			else
  				opp = temp_opp;
  		}
  	}
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
545
546
547
548
  
  	/* Increment the reference count of OPP */
  	if (!IS_ERR(opp))
  		dev_pm_opp_get(opp);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
549
  	mutex_unlock(&opp_table->lock);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
550
  	dev_pm_opp_put_opp_table(opp_table);
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
551

e1f60b292   Nishanth Menon   PM: Introduce lib...
552
553
554
555
556
  	if (!IS_ERR(opp))
  		*freq = opp->rate;
  
  	return opp;
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
557
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
e1f60b292   Nishanth Menon   PM: Introduce lib...
558

2f36bde0f   Andrew-sh.Cheng   OPP: Introduce de...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  /**
   * dev_pm_opp_find_freq_ceil_by_volt() - Find OPP with highest frequency for
   *					 target voltage.
   * @dev:	Device for which we do this operation.
   * @u_volt:	Target voltage.
   *
   * Search for OPP with highest (ceil) frequency and has voltage <= u_volt.
   *
   * Return: matching *opp, else returns ERR_PTR in case of error which should be
   * handled using IS_ERR.
   *
   * Error return values can be:
   * EINVAL:	bad parameters
   *
   * The callers are required to call dev_pm_opp_put() for the returned OPP after
   * use.
   */
  struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
  						     unsigned long u_volt)
  {
  	struct opp_table *opp_table;
  	struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
  
  	if (!dev || !u_volt) {
  		dev_err(dev, "%s: Invalid argument volt=%lu
  ", __func__,
  			u_volt);
  		return ERR_PTR(-EINVAL);
  	}
  
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table))
  		return ERR_CAST(opp_table);
  
  	mutex_lock(&opp_table->lock);
  
  	list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
  		if (temp_opp->available) {
  			if (temp_opp->supplies[0].u_volt > u_volt)
  				break;
  			opp = temp_opp;
  		}
  	}
  
  	/* Increment the reference count of OPP */
  	if (!IS_ERR(opp))
  		dev_pm_opp_get(opp);
  
  	mutex_unlock(&opp_table->lock);
  	dev_pm_opp_put_opp_table(opp_table);
  
  	return opp;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil_by_volt);
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
613
  static int _set_opp_voltage(struct device *dev, struct regulator *reg,
ce31781a7   Viresh Kumar   PM / OPP: Pass st...
614
  			    struct dev_pm_opp_supply *supply)
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
615
616
617
618
619
620
621
622
623
624
  {
  	int ret;
  
  	/* Regulator not available for device */
  	if (IS_ERR(reg)) {
  		dev_dbg(dev, "%s: regulator not available: %ld
  ", __func__,
  			PTR_ERR(reg));
  		return 0;
  	}
ce31781a7   Viresh Kumar   PM / OPP: Pass st...
625
626
627
  	dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu
  ", __func__,
  		supply->u_volt_min, supply->u_volt, supply->u_volt_max);
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
628

ce31781a7   Viresh Kumar   PM / OPP: Pass st...
629
630
  	ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
  					    supply->u_volt, supply->u_volt_max);
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
631
632
633
  	if (ret)
  		dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d
  ",
ce31781a7   Viresh Kumar   PM / OPP: Pass st...
634
635
  			__func__, supply->u_volt_min, supply->u_volt,
  			supply->u_volt_max, ret);
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
636
637
638
  
  	return ret;
  }
285881b51   Viresh Kumar   PM / OPP: Remove ...
639
640
  static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
  					    unsigned long freq)
947355850   Viresh Kumar   PM / OPP: Separat...
641
642
643
644
645
646
647
648
649
650
651
652
  {
  	int ret;
  
  	ret = clk_set_rate(clk, freq);
  	if (ret) {
  		dev_err(dev, "%s: failed to set clock rate: %d
  ", __func__,
  			ret);
  	}
  
  	return ret;
  }
8d45719ca   Kamil Konieczny   opp: core: add re...
653
  static int _generic_set_opp_regulator(struct opp_table *opp_table,
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
654
655
656
657
658
  				      struct device *dev,
  				      unsigned long old_freq,
  				      unsigned long freq,
  				      struct dev_pm_opp_supply *old_supply,
  				      struct dev_pm_opp_supply *new_supply)
947355850   Viresh Kumar   PM / OPP: Separat...
659
  {
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
660
  	struct regulator *reg = opp_table->regulators[0];
947355850   Viresh Kumar   PM / OPP: Separat...
661
662
663
  	int ret;
  
  	/* This function only supports single regulator per device */
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
664
  	if (WARN_ON(opp_table->regulator_count > 1)) {
947355850   Viresh Kumar   PM / OPP: Separat...
665
666
667
668
669
670
  		dev_err(dev, "multiple regulators are not supported
  ");
  		return -EINVAL;
  	}
  
  	/* Scaling up? Scale voltage before frequency */
c5c2a97b3   Waldemar Rymarkiewicz   PM / OPP: Update ...
671
  	if (freq >= old_freq) {
947355850   Viresh Kumar   PM / OPP: Separat...
672
673
674
675
676
677
  		ret = _set_opp_voltage(dev, reg, new_supply);
  		if (ret)
  			goto restore_voltage;
  	}
  
  	/* Change frequency */
285881b51   Viresh Kumar   PM / OPP: Remove ...
678
  	ret = _generic_set_opp_clk_only(dev, opp_table->clk, freq);
947355850   Viresh Kumar   PM / OPP: Separat...
679
680
681
682
683
684
685
686
687
  	if (ret)
  		goto restore_voltage;
  
  	/* Scaling down? Scale voltage after frequency */
  	if (freq < old_freq) {
  		ret = _set_opp_voltage(dev, reg, new_supply);
  		if (ret)
  			goto restore_freq;
  	}
8d45719ca   Kamil Konieczny   opp: core: add re...
688
689
690
691
  	/*
  	 * Enable the regulator after setting its voltages, otherwise it breaks
  	 * some boot-enabled regulators.
  	 */
72f80ce4e   Viresh Kumar   opp: Rename regul...
692
  	if (unlikely(!opp_table->enabled)) {
8d45719ca   Kamil Konieczny   opp: core: add re...
693
694
695
  		ret = regulator_enable(reg);
  		if (ret < 0)
  			dev_warn(dev, "Failed to enable regulator: %d", ret);
8d45719ca   Kamil Konieczny   opp: core: add re...
696
  	}
947355850   Viresh Kumar   PM / OPP: Separat...
697
698
699
  	return 0;
  
  restore_freq:
285881b51   Viresh Kumar   PM / OPP: Remove ...
700
  	if (_generic_set_opp_clk_only(dev, opp_table->clk, old_freq))
947355850   Viresh Kumar   PM / OPP: Separat...
701
702
703
704
705
  		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)
  ",
  			__func__, old_freq);
  restore_voltage:
  	/* This shouldn't harm even if the voltages weren't updated earlier */
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
706
  	if (old_supply)
947355850   Viresh Kumar   PM / OPP: Separat...
707
708
709
710
  		_set_opp_voltage(dev, reg, old_supply);
  
  	return ret;
  }
b00e667a6   Viresh Kumar   opp: Remove bandw...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
  static int _set_opp_bw(const struct opp_table *opp_table,
  		       struct dev_pm_opp *opp, struct device *dev, bool remove)
  {
  	u32 avg, peak;
  	int i, ret;
  
  	if (!opp_table->paths)
  		return 0;
  
  	for (i = 0; i < opp_table->path_count; i++) {
  		if (remove) {
  			avg = 0;
  			peak = 0;
  		} else {
  			avg = opp->bandwidth[i].avg;
  			peak = opp->bandwidth[i].peak;
  		}
  		ret = icc_set_bw(opp_table->paths[i], avg, peak);
  		if (ret) {
  			dev_err(dev, "Failed to %s bandwidth[%d]: %d
  ",
  				remove ? "remove" : "set", i, ret);
  			return ret;
  		}
  	}
  
  	return 0;
  }
7e535993f   Viresh Kumar   OPP: Separate out...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  static int _set_opp_custom(const struct opp_table *opp_table,
  			   struct device *dev, unsigned long old_freq,
  			   unsigned long freq,
  			   struct dev_pm_opp_supply *old_supply,
  			   struct dev_pm_opp_supply *new_supply)
  {
  	struct dev_pm_set_opp_data *data;
  	int size;
  
  	data = opp_table->set_opp_data;
  	data->regulators = opp_table->regulators;
  	data->regulator_count = opp_table->regulator_count;
  	data->clk = opp_table->clk;
  	data->dev = dev;
  
  	data->old_opp.rate = old_freq;
  	size = sizeof(*old_supply) * opp_table->regulator_count;
560d1bcad   Dmitry Osipenko   opp: Don't use IS...
756
  	if (!old_supply)
7e535993f   Viresh Kumar   OPP: Separate out...
757
758
759
760
761
762
763
764
765
  		memset(data->old_opp.supplies, 0, size);
  	else
  		memcpy(data->old_opp.supplies, old_supply, size);
  
  	data->new_opp.rate = freq;
  	memcpy(data->new_opp.supplies, new_supply, size);
  
  	return opp_table->set_opp(data);
  }
60cdeae0d   Stephan Gerhold   opp: Reduce code ...
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  static int _set_required_opp(struct device *dev, struct device *pd_dev,
  			     struct dev_pm_opp *opp, int i)
  {
  	unsigned int pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
  	int ret;
  
  	if (!pd_dev)
  		return 0;
  
  	ret = dev_pm_genpd_set_performance_state(pd_dev, pstate);
  	if (ret) {
  		dev_err(dev, "Failed to set performance rate of %s: %d (%d)
  ",
  			dev_name(pd_dev), pstate, ret);
  	}
  
  	return ret;
  }
ca1b5d77b   Viresh Kumar   OPP: Configure al...
784
785
786
  /* This is only called for PM domain for now */
  static int _set_required_opps(struct device *dev,
  			      struct opp_table *opp_table,
2c59138c2   Stephan Gerhold   opp: Set required...
787
  			      struct dev_pm_opp *opp, bool up)
ca1b5d77b   Viresh Kumar   OPP: Configure al...
788
789
790
  {
  	struct opp_table **required_opp_tables = opp_table->required_opp_tables;
  	struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
ca1b5d77b   Viresh Kumar   OPP: Configure al...
791
792
793
794
795
796
  	int i, ret = 0;
  
  	if (!required_opp_tables)
  		return 0;
  
  	/* Single genpd case */
60cdeae0d   Stephan Gerhold   opp: Reduce code ...
797
798
  	if (!genpd_virt_devs)
  		return _set_required_opp(dev, dev, opp, 0);
ca1b5d77b   Viresh Kumar   OPP: Configure al...
799
800
801
802
803
804
805
806
  
  	/* Multiple genpd case */
  
  	/*
  	 * Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev
  	 * after it is freed from another thread.
  	 */
  	mutex_lock(&opp_table->genpd_virt_dev_lock);
2c59138c2   Stephan Gerhold   opp: Set required...
807
808
809
810
811
812
813
814
815
816
817
818
  	/* Scaling up? Set required OPPs in normal order, else reverse */
  	if (up) {
  		for (i = 0; i < opp_table->required_opp_count; i++) {
  			ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
  			if (ret)
  				break;
  		}
  	} else {
  		for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
  			ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
  			if (ret)
  				break;
ca1b5d77b   Viresh Kumar   OPP: Configure al...
819
820
  		}
  	}
2c59138c2   Stephan Gerhold   opp: Set required...
821

ca1b5d77b   Viresh Kumar   OPP: Configure al...
822
823
824
825
  	mutex_unlock(&opp_table->genpd_virt_dev_lock);
  
  	return ret;
  }
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
826
  /**
3ae1f39ae   Sibi Sankar   OPP: Add and expo...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
   * dev_pm_opp_set_bw() - sets bandwidth levels corresponding to an opp
   * @dev:	device for which we do this operation
   * @opp:	opp based on which the bandwidth levels are to be configured
   *
   * This configures the bandwidth to the levels specified by the OPP. However
   * if the OPP specified is NULL the bandwidth levels are cleared out.
   *
   * Return: 0 on success or a negative error value.
   */
  int dev_pm_opp_set_bw(struct device *dev, struct dev_pm_opp *opp)
  {
  	struct opp_table *opp_table;
  	int ret;
  
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		dev_err(dev, "%s: device opp table doesn't exist
  ", __func__);
  		return PTR_ERR(opp_table);
  	}
  
  	if (opp)
  		ret = _set_opp_bw(opp_table, opp, dev, false);
  	else
  		ret = _set_opp_bw(opp_table, NULL, dev, true);
  
  	dev_pm_opp_put_opp_table(opp_table);
  	return ret;
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_bw);
f3364e17d   Viresh Kumar   opp: Split out _o...
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
  static int _opp_set_rate_zero(struct device *dev, struct opp_table *opp_table)
  {
  	int ret;
  
  	if (!opp_table->enabled)
  		return 0;
  
  	/*
  	 * Some drivers need to support cases where some platforms may
  	 * have OPP table for the device, while others don't and
  	 * opp_set_rate() just needs to behave like clk_set_rate().
  	 */
  	if (!_get_opp_count(opp_table))
  		return 0;
  
  	ret = _set_opp_bw(opp_table, NULL, dev, true);
  	if (ret)
  		return ret;
  
  	if (opp_table->regulators)
  		regulator_disable(opp_table->regulators[0]);
2c59138c2   Stephan Gerhold   opp: Set required...
878
  	ret = _set_required_opps(dev, opp_table, NULL, false);
f3364e17d   Viresh Kumar   opp: Split out _o...
879
880
881
882
  
  	opp_table->enabled = false;
  	return ret;
  }
3ae1f39ae   Sibi Sankar   OPP: Add and expo...
883
  /**
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
884
885
886
887
   * dev_pm_opp_set_rate() - Configure new OPP based on frequency
   * @dev:	 device for which we do this operation
   * @target_freq: frequency to achieve
   *
b3e3759ee   Stephen Boyd   opp: Don't overwr...
888
889
890
891
892
   * This configures the power-supplies to the levels specified by the OPP
   * corresponding to the target_freq, and programs the clock to a value <=
   * target_freq, as rounded by clk_round_rate(). Device wanting to run at fmax
   * provided by the opp, should have already rounded to the target OPP's
   * frequency.
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
893
894
895
   */
  int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
896
  	struct opp_table *opp_table;
b3e3759ee   Stephen Boyd   opp: Don't overwr...
897
  	unsigned long freq, old_freq, temp_freq;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
898
  	struct dev_pm_opp *old_opp, *opp;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
899
  	struct clk *clk;
b00e667a6   Viresh Kumar   opp: Remove bandw...
900
  	int ret;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
901

052c6f191   Viresh Kumar   PM / OPP: Move aw...
902
903
904
905
906
907
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		dev_err(dev, "%s: device opp doesn't exist
  ", __func__);
  		return PTR_ERR(opp_table);
  	}
cd7ea5828   Rajendra Nayak   opp: Make dev_pm_...
908
  	if (unlikely(!target_freq)) {
f3364e17d   Viresh Kumar   opp: Split out _o...
909
  		ret = _opp_set_rate_zero(dev, opp_table);
cd7ea5828   Rajendra Nayak   opp: Make dev_pm_...
910
911
  		goto put_opp_table;
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
912
913
914
915
916
917
918
919
  	clk = opp_table->clk;
  	if (IS_ERR(clk)) {
  		dev_err(dev, "%s: No clock available for the device
  ",
  			__func__);
  		ret = PTR_ERR(clk);
  		goto put_opp_table;
  	}
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
920
921
922
923
924
925
926
927
  
  	freq = clk_round_rate(clk, target_freq);
  	if ((long)freq <= 0)
  		freq = target_freq;
  
  	old_freq = clk_get_rate(clk);
  
  	/* Return early if nothing to do */
10b217365   Viresh Kumar   opp: Reuse the en...
928
929
930
931
932
933
  	if (opp_table->enabled && old_freq == freq) {
  		dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do
  ",
  			__func__, freq);
  		ret = 0;
  		goto put_opp_table;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
934
  	}
aca48b61f   Rajendra Nayak   opp: Manage empty...
935
936
937
938
939
940
941
942
943
944
945
  	/*
  	 * For IO devices which require an OPP on some platforms/SoCs
  	 * while just needing to scale the clock on some others
  	 * we look for empty OPP tables with just a clock handle and
  	 * scale only the clk. This makes dev_pm_opp_set_rate()
  	 * equivalent to a clk_set_rate()
  	 */
  	if (!_get_opp_count(opp_table)) {
  		ret = _generic_set_opp_clk_only(dev, clk, freq);
  		goto put_opp_table;
  	}
b3e3759ee   Stephen Boyd   opp: Don't overwr...
946
947
  	temp_freq = old_freq;
  	old_opp = _find_freq_ceil(opp_table, &temp_freq);
4df27c918   Arnd Bergmann   PM / OPP: avoid m...
948
  	if (IS_ERR(old_opp)) {
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
949
950
951
952
  		dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)
  ",
  			__func__, old_freq, PTR_ERR(old_opp));
  	}
b3e3759ee   Stephen Boyd   opp: Don't overwr...
953
954
  	temp_freq = freq;
  	opp = _find_freq_ceil(opp_table, &temp_freq);
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
955
956
957
958
959
  	if (IS_ERR(opp)) {
  		ret = PTR_ERR(opp);
  		dev_err(dev, "%s: failed to find OPP for freq %lu (%d)
  ",
  			__func__, freq, ret);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
960
  		goto put_old_opp;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
961
  	}
947355850   Viresh Kumar   PM / OPP: Separat...
962
963
964
  	dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz
  ", __func__,
  		old_freq, freq);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
965

ca1b5d77b   Viresh Kumar   OPP: Configure al...
966
  	/* Scaling up? Configure required OPPs before frequency */
faef080f6   Viresh Kumar   PM / OPP: Update ...
967
  	if (freq >= old_freq) {
2c59138c2   Stephan Gerhold   opp: Set required...
968
  		ret = _set_required_opps(dev, opp_table, opp, true);
ca1b5d77b   Viresh Kumar   OPP: Configure al...
969
970
971
  		if (ret)
  			goto put_opp;
  	}
7e535993f   Viresh Kumar   OPP: Separate out...
972
973
974
975
976
  	if (opp_table->set_opp) {
  		ret = _set_opp_custom(opp_table, dev, old_freq, freq,
  				      IS_ERR(old_opp) ? NULL : old_opp->supplies,
  				      opp->supplies);
  	} else if (opp_table->regulators) {
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
977
978
979
980
  		ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq,
  						 IS_ERR(old_opp) ? NULL : old_opp->supplies,
  						 opp->supplies);
  	} else {
7e535993f   Viresh Kumar   OPP: Separate out...
981
  		/* Only frequency scaling */
285881b51   Viresh Kumar   PM / OPP: Remove ...
982
  		ret = _generic_set_opp_clk_only(dev, clk, freq);
ca1b5d77b   Viresh Kumar   OPP: Configure al...
983
  	}
c74b32fad   Viresh Kumar   PM / OPP: Reorgan...
984

ca1b5d77b   Viresh Kumar   OPP: Configure al...
985
986
  	/* Scaling down? Configure required OPPs after frequency */
  	if (!ret && freq < old_freq) {
2c59138c2   Stephan Gerhold   opp: Set required...
987
  		ret = _set_required_opps(dev, opp_table, opp, false);
ca1b5d77b   Viresh Kumar   OPP: Configure al...
988
989
990
  		if (ret)
  			dev_err(dev, "Failed to set required opps: %d
  ", ret);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
991
  	}
72f80ce4e   Viresh Kumar   opp: Rename regul...
992
  	if (!ret) {
b00e667a6   Viresh Kumar   opp: Remove bandw...
993
  		ret = _set_opp_bw(opp_table, opp, dev, false);
72f80ce4e   Viresh Kumar   opp: Rename regul...
994
995
996
  		if (!ret)
  			opp_table->enabled = true;
  	}
fe2af4025   Georgi Djakov   opp: Update the b...
997

ca1b5d77b   Viresh Kumar   OPP: Configure al...
998
  put_opp:
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
999
  	dev_pm_opp_put(opp);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1000
  put_old_opp:
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
1001
1002
  	if (!IS_ERR(old_opp))
  		dev_pm_opp_put(old_opp);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1003
  put_opp_table:
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1004
  	dev_pm_opp_put_opp_table(opp_table);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1005
  	return ret;
6a0712f6f   Viresh Kumar   PM / OPP: Add dev...
1006
1007
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1008
  /* OPP-dev Helpers */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1009
1010
  static void _remove_opp_dev(struct opp_device *opp_dev,
  			    struct opp_table *opp_table)
064416586   Viresh Kumar   PM / OPP: Add OPP...
1011
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1012
1013
  	opp_debug_unregister(opp_dev, opp_table);
  	list_del(&opp_dev->node);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1014
  	kfree(opp_dev);
064416586   Viresh Kumar   PM / OPP: Add OPP...
1015
  }
283d55e68   Viresh Kumar   OPP: Prevent crea...
1016
1017
  static struct opp_device *_add_opp_dev_unlocked(const struct device *dev,
  						struct opp_table *opp_table)
064416586   Viresh Kumar   PM / OPP: Add OPP...
1018
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1019
  	struct opp_device *opp_dev;
064416586   Viresh Kumar   PM / OPP: Add OPP...
1020

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1021
1022
  	opp_dev = kzalloc(sizeof(*opp_dev), GFP_KERNEL);
  	if (!opp_dev)
064416586   Viresh Kumar   PM / OPP: Add OPP...
1023
  		return NULL;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1024
1025
  	/* Initialize opp-dev */
  	opp_dev->dev = dev;
3d2556992   Viresh Kumar   OPP: Protect dev_...
1026

052c6f191   Viresh Kumar   PM / OPP: Move aw...
1027
  	list_add(&opp_dev->node, &opp_table->dev_list);
064416586   Viresh Kumar   PM / OPP: Add OPP...
1028

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1029
  	/* Create debugfs entries for the opp_table */
a2dea4cb9   Greg Kroah-Hartman   opp: no need to c...
1030
  	opp_debug_register(opp_dev, opp_table);
283d55e68   Viresh Kumar   OPP: Prevent crea...
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
  
  	return opp_dev;
  }
  
  struct opp_device *_add_opp_dev(const struct device *dev,
  				struct opp_table *opp_table)
  {
  	struct opp_device *opp_dev;
  
  	mutex_lock(&opp_table->lock);
  	opp_dev = _add_opp_dev_unlocked(dev, opp_table);
3d2556992   Viresh Kumar   OPP: Protect dev_...
1042
  	mutex_unlock(&opp_table->lock);
deaa51465   Viresh Kumar   PM / OPP: Add deb...
1043

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1044
  	return opp_dev;
064416586   Viresh Kumar   PM / OPP: Add OPP...
1045
  }
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1046
  static struct opp_table *_allocate_opp_table(struct device *dev, int index)
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1047
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1048
1049
  	struct opp_table *opp_table;
  	struct opp_device *opp_dev;
d54974c25   Viresh Kumar   PM / OPP: Manage ...
1050
  	int ret;
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1051
1052
  
  	/*
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1053
  	 * Allocate a new OPP table. In the infrequent case where a new
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1054
1055
  	 * device is needed to be added, we pay this penalty.
  	 */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1056
1057
  	opp_table = kzalloc(sizeof(*opp_table), GFP_KERNEL);
  	if (!opp_table)
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1058
  		return ERR_PTR(-ENOMEM);
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1059

3d2556992   Viresh Kumar   OPP: Protect dev_...
1060
  	mutex_init(&opp_table->lock);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1061
  	mutex_init(&opp_table->genpd_virt_dev_lock);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1062
  	INIT_LIST_HEAD(&opp_table->dev_list);
064416586   Viresh Kumar   PM / OPP: Add OPP...
1063

46f48aca2   Viresh Kumar   OPP: Fix missing ...
1064
1065
  	/* Mark regulator count uninitialized */
  	opp_table->regulator_count = -1;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1066
1067
  	opp_dev = _add_opp_dev(dev, opp_table);
  	if (!opp_dev) {
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1068
1069
  		ret = -ENOMEM;
  		goto err;
064416586   Viresh Kumar   PM / OPP: Add OPP...
1070
  	}
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1071
  	_of_init_opp_table(opp_table, dev, index);
50f8cfbd5   Viresh Kumar   PM / OPP: Parse c...
1072

d54974c25   Viresh Kumar   PM / OPP: Manage ...
1073
  	/* Find clk for the device */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1074
1075
1076
  	opp_table->clk = clk_get(dev, NULL);
  	if (IS_ERR(opp_table->clk)) {
  		ret = PTR_ERR(opp_table->clk);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1077
  		if (ret == -EPROBE_DEFER)
e8322837a   Quanyang Wang   opp: fix memory l...
1078
  			goto remove_opp_dev;
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1079
1080
1081
  
  		dev_dbg(dev, "%s: Couldn't find clock: %d
  ", __func__, ret);
d54974c25   Viresh Kumar   PM / OPP: Manage ...
1082
  	}
6d3f922c4   Georgi Djakov   opp: Add support ...
1083
1084
  	/* Find interconnect path(s) for the device */
  	ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1085
1086
  	if (ret) {
  		if (ret == -EPROBE_DEFER)
1a58c171a   Viresh Kumar   opp: Call the mis...
1087
  			goto put_clk;
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1088

6d3f922c4   Georgi Djakov   opp: Add support ...
1089
1090
1091
  		dev_warn(dev, "%s: Error finding interconnect paths: %d
  ",
  			 __func__, ret);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1092
  	}
6d3f922c4   Georgi Djakov   opp: Add support ...
1093

052c6f191   Viresh Kumar   PM / OPP: Move aw...
1094
  	BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1095
  	INIT_LIST_HEAD(&opp_table->opp_list);
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1096
  	kref_init(&opp_table->kref);
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1097

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1098
  	/* Secure the device table modification */
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1099
  	list_add(&opp_table->node, &opp_tables);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1100
  	return opp_table;
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1101

1a58c171a   Viresh Kumar   opp: Call the mis...
1102
1103
1104
  put_clk:
  	if (!IS_ERR(opp_table->clk))
  		clk_put(opp_table->clk);
e8322837a   Quanyang Wang   opp: fix memory l...
1105
1106
  remove_opp_dev:
  	_remove_opp_dev(opp_dev, opp_table);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1107
1108
1109
  err:
  	kfree(opp_table);
  	return ERR_PTR(ret);
07cce74a7   Viresh Kumar   PM / OPP: handle ...
1110
  }
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1111
  void _get_opp_table_kref(struct opp_table *opp_table)
b6160e269   Viresh Kumar   PM / OPP: Split o...
1112
  {
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1113
1114
  	kref_get(&opp_table->kref);
  }
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1115
  static struct opp_table *_opp_get_opp_table(struct device *dev, int index)
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1116
1117
1118
1119
1120
  {
  	struct opp_table *opp_table;
  
  	/* Hold our table modification lock here */
  	mutex_lock(&opp_table_lock);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1121
1122
  	opp_table = _find_opp_table_unlocked(dev);
  	if (!IS_ERR(opp_table))
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1123
  		goto unlock;
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1124

283d55e68   Viresh Kumar   OPP: Prevent crea...
1125
1126
1127
1128
  	opp_table = _managed_opp(dev, index);
  	if (opp_table) {
  		if (!_add_opp_dev_unlocked(dev, opp_table)) {
  			dev_pm_opp_put_opp_table(opp_table);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1129
  			opp_table = ERR_PTR(-ENOMEM);
283d55e68   Viresh Kumar   OPP: Prevent crea...
1130
1131
1132
  		}
  		goto unlock;
  	}
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1133
  	opp_table = _allocate_opp_table(dev, index);
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1134
1135
1136
1137
1138
1139
  
  unlock:
  	mutex_unlock(&opp_table_lock);
  
  	return opp_table;
  }
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1140
1141
1142
1143
1144
  
  struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
  {
  	return _opp_get_opp_table(dev, 0);
  }
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1145
  EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table);
eb7c8743d   Viresh Kumar   OPP: Pass index t...
1146
1147
1148
1149
1150
  struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev,
  						   int index)
  {
  	return _opp_get_opp_table(dev, index);
  }
b83c1899a   Viresh Kumar   PM / OPP: Use dev...
1151
  static void _opp_table_kref_release(struct kref *kref)
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1152
1153
  {
  	struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
cdd6ed90c   Viresh Kumar   OPP: Use a single...
1154
  	struct opp_device *opp_dev, *temp;
6d3f922c4   Georgi Djakov   opp: Add support ...
1155
  	int i;
b6160e269   Viresh Kumar   PM / OPP: Split o...
1156

e0df59de6   Viresh Kumar   opp: Reduce the s...
1157
1158
1159
  	/* Drop the lock as soon as we can */
  	list_del(&opp_table->node);
  	mutex_unlock(&opp_table_lock);
5d6d106fa   Viresh Kumar   OPP: Populate req...
1160
  	_of_clear_opp_table(opp_table);
b6160e269   Viresh Kumar   PM / OPP: Split o...
1161
1162
1163
  	/* Release clk */
  	if (!IS_ERR(opp_table->clk))
  		clk_put(opp_table->clk);
6d3f922c4   Georgi Djakov   opp: Add support ...
1164
1165
1166
1167
1168
  	if (opp_table->paths) {
  		for (i = 0; i < opp_table->path_count; i++)
  			icc_put(opp_table->paths[i]);
  		kfree(opp_table->paths);
  	}
cdd6ed90c   Viresh Kumar   OPP: Use a single...
1169
  	WARN_ON(!list_empty(&opp_table->opp_list));
b6160e269   Viresh Kumar   PM / OPP: Split o...
1170

cdd6ed90c   Viresh Kumar   OPP: Use a single...
1171
1172
1173
1174
1175
1176
1177
  	list_for_each_entry_safe(opp_dev, temp, &opp_table->dev_list, node) {
  		/*
  		 * The OPP table is getting removed, drop the performance state
  		 * constraints.
  		 */
  		if (opp_table->genpd_performance_state)
  			dev_pm_genpd_set_performance_state((struct device *)(opp_dev->dev), 0);
b6160e269   Viresh Kumar   PM / OPP: Split o...
1178

cdd6ed90c   Viresh Kumar   OPP: Use a single...
1179
1180
  		_remove_opp_dev(opp_dev, opp_table);
  	}
b6160e269   Viresh Kumar   PM / OPP: Split o...
1181

4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1182
  	mutex_destroy(&opp_table->genpd_virt_dev_lock);
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1183
  	mutex_destroy(&opp_table->lock);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1184
  	kfree(opp_table);
f067a982c   Viresh Kumar   PM / OPP: Add 'st...
1185
1186
1187
1188
1189
1190
1191
1192
  }
  
  void dev_pm_opp_put_opp_table(struct opp_table *opp_table)
  {
  	kref_put_mutex(&opp_table->kref, _opp_table_kref_release,
  		       &opp_table_lock);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_put_opp_table);
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1193
  void _opp_free(struct dev_pm_opp *opp)
969fceb3c   Viresh Kumar   PM / OPP: Add lig...
1194
1195
  {
  	kfree(opp);
969fceb3c   Viresh Kumar   PM / OPP: Add lig...
1196
  }
1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1197
1198
  static void _opp_kref_release(struct dev_pm_opp *opp,
  			      struct opp_table *opp_table)
129eec55d   Viresh Kumar   PM / OPP Introduc...
1199
1200
1201
1202
1203
  {
  	/*
  	 * Notify the changes in the availability of the operable
  	 * frequency/voltage list.
  	 */
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1204
  	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
da544b61e   Viresh Kumar   OPP: Populate OPP...
1205
  	_of_opp_free_required_opps(opp_table, opp);
deaa51465   Viresh Kumar   PM / OPP: Add deb...
1206
  	opp_debug_remove_one(opp);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1207
1208
  	list_del(&opp->node);
  	kfree(opp);
1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1209
  }
129eec55d   Viresh Kumar   PM / OPP Introduc...
1210

1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  static void _opp_kref_release_unlocked(struct kref *kref)
  {
  	struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
  	struct opp_table *opp_table = opp->opp_table;
  
  	_opp_kref_release(opp, opp_table);
  }
  
  static void _opp_kref_release_locked(struct kref *kref)
  {
  	struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
  	struct opp_table *opp_table = opp->opp_table;
  
  	_opp_kref_release(opp, opp_table);
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1225
  	mutex_unlock(&opp_table->lock);
129eec55d   Viresh Kumar   PM / OPP Introduc...
1226
  }
a88bd2a51   Viresh Kumar   PM / OPP: Impleme...
1227
  void dev_pm_opp_get(struct dev_pm_opp *opp)
8a31d9d94   Viresh Kumar   PM / OPP: Update ...
1228
1229
1230
  {
  	kref_get(&opp->kref);
  }
7034764a1   Viresh Kumar   PM / OPP: Add 'st...
1231
1232
  void dev_pm_opp_put(struct dev_pm_opp *opp)
  {
1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1233
1234
  	kref_put_mutex(&opp->kref, _opp_kref_release_locked,
  		       &opp->opp_table->lock);
7034764a1   Viresh Kumar   PM / OPP: Add 'st...
1235
1236
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_put);
1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1237
1238
1239
1240
  static void dev_pm_opp_put_unlocked(struct dev_pm_opp *opp)
  {
  	kref_put(&opp->kref, _opp_kref_release_unlocked);
  }
129eec55d   Viresh Kumar   PM / OPP Introduc...
1241
  /**
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1242
   * dev_pm_opp_remove()  - Remove an OPP from OPP table
129eec55d   Viresh Kumar   PM / OPP Introduc...
1243
1244
1245
   * @dev:	device for which we do this operation
   * @freq:	OPP to remove with matching 'freq'
   *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1246
   * This function removes an opp from the opp table.
129eec55d   Viresh Kumar   PM / OPP Introduc...
1247
1248
1249
1250
   */
  void dev_pm_opp_remove(struct device *dev, unsigned long freq)
  {
  	struct dev_pm_opp *opp;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1251
  	struct opp_table *opp_table;
129eec55d   Viresh Kumar   PM / OPP Introduc...
1252
  	bool found = false;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1253
1254
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table))
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1255
  		return;
129eec55d   Viresh Kumar   PM / OPP Introduc...
1256

37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1257
  	mutex_lock(&opp_table->lock);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1258
  	list_for_each_entry(opp, &opp_table->opp_list, node) {
129eec55d   Viresh Kumar   PM / OPP Introduc...
1259
1260
1261
1262
1263
  		if (opp->rate == freq) {
  			found = true;
  			break;
  		}
  	}
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1264
  	mutex_unlock(&opp_table->lock);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1265
1266
  	if (found) {
  		dev_pm_opp_put(opp);
0ad8c6239   Viresh Kumar   OPP: Don't take O...
1267
1268
1269
  
  		/* Drop the reference taken by dev_pm_opp_add() */
  		dev_pm_opp_put_opp_table(opp_table);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1270
  	} else {
129eec55d   Viresh Kumar   PM / OPP Introduc...
1271
1272
1273
  		dev_warn(dev, "%s: Couldn't find OPP with freq: %lu
  ",
  			 __func__, freq);
129eec55d   Viresh Kumar   PM / OPP Introduc...
1274
  	}
0ad8c6239   Viresh Kumar   OPP: Don't take O...
1275
  	/* Drop the reference taken by _find_opp_table() */
5b650b388   Viresh Kumar   PM / OPP: Take kr...
1276
  	dev_pm_opp_put_opp_table(opp_table);
129eec55d   Viresh Kumar   PM / OPP Introduc...
1277
1278
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
922ff0759   Viresh Kumar   opp: Don't drop r...
1279
  bool _opp_remove_all_static(struct opp_table *opp_table)
03758d602   Viresh Kumar   opp: Replace list...
1280
1281
  {
  	struct dev_pm_opp *opp, *tmp;
922ff0759   Viresh Kumar   opp: Don't drop r...
1282
  	bool ret = true;
03758d602   Viresh Kumar   opp: Replace list...
1283
1284
  
  	mutex_lock(&opp_table->lock);
922ff0759   Viresh Kumar   opp: Don't drop r...
1285
1286
1287
1288
1289
1290
  	if (!opp_table->parsed_static_opps) {
  		ret = false;
  		goto unlock;
  	}
  
  	if (--opp_table->parsed_static_opps)
03758d602   Viresh Kumar   opp: Replace list...
1291
1292
1293
1294
1295
1296
1297
1298
1299
  		goto unlock;
  
  	list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
  		if (!opp->dynamic)
  			dev_pm_opp_put_unlocked(opp);
  	}
  
  unlock:
  	mutex_unlock(&opp_table->lock);
922ff0759   Viresh Kumar   opp: Don't drop r...
1300
1301
  
  	return ret;
03758d602   Viresh Kumar   opp: Replace list...
1302
  }
1690d8bb9   Viresh Kumar   cpufreq: scpi/scm...
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  /**
   * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
   * @dev:	device for which we do this operation
   *
   * This function removes all dynamically created OPPs from the opp table.
   */
  void dev_pm_opp_remove_all_dynamic(struct device *dev)
  {
  	struct opp_table *opp_table;
  	struct dev_pm_opp *opp, *temp;
  	int count = 0;
  
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table))
  		return;
  
  	mutex_lock(&opp_table->lock);
  	list_for_each_entry_safe(opp, temp, &opp_table->opp_list, node) {
  		if (opp->dynamic) {
  			dev_pm_opp_put_unlocked(opp);
  			count++;
  		}
  	}
  	mutex_unlock(&opp_table->lock);
  
  	/* Drop the references taken by dev_pm_opp_add() */
  	while (count--)
  		dev_pm_opp_put_opp_table(opp_table);
  
  	/* Drop the reference taken by _find_opp_table() */
  	dev_pm_opp_put_opp_table(opp_table);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1336
  struct dev_pm_opp *_opp_allocate(struct opp_table *table)
e1f60b292   Nishanth Menon   PM: Introduce lib...
1337
  {
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1338
  	struct dev_pm_opp *opp;
6d3f922c4   Georgi Djakov   opp: Add support ...
1339
  	int supply_count, supply_size, icc_size;
e1f60b292   Nishanth Menon   PM: Introduce lib...
1340

dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1341
  	/* Allocate space for at least one supply */
6d3f922c4   Georgi Djakov   opp: Add support ...
1342
1343
1344
  	supply_count = table->regulator_count > 0 ? table->regulator_count : 1;
  	supply_size = sizeof(*opp->supplies) * supply_count;
  	icc_size = sizeof(*opp->bandwidth) * table->path_count;
e1f60b292   Nishanth Menon   PM: Introduce lib...
1345

dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1346
  	/* allocate new OPP node and supplies structures */
6d3f922c4   Georgi Djakov   opp: Add support ...
1347
  	opp = kzalloc(sizeof(*opp) + supply_size + icc_size, GFP_KERNEL);
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1348
  	if (!opp)
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1349
  		return NULL;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1350

dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1351
1352
  	/* Put the supplies at the end of the OPP structure as an empty array */
  	opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
6d3f922c4   Georgi Djakov   opp: Add support ...
1353
1354
  	if (icc_size)
  		opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->supplies + supply_count);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1355
  	INIT_LIST_HEAD(&opp->node);
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1356
1357
  	return opp;
  }
7d34d56ef   Viresh Kumar   PM / OPP: Disable...
1358
  static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1359
  					 struct opp_table *opp_table)
7d34d56ef   Viresh Kumar   PM / OPP: Disable...
1360
  {
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1361
1362
  	struct regulator *reg;
  	int i;
90e3577b5   Viresh Kumar   OPP: Use opp_tabl...
1363
1364
  	if (!opp_table->regulators)
  		return true;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
  	for (i = 0; i < opp_table->regulator_count; i++) {
  		reg = opp_table->regulators[i];
  
  		if (!regulator_is_supported_voltage(reg,
  					opp->supplies[i].u_volt_min,
  					opp->supplies[i].u_volt_max)) {
  			pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator
  ",
  				__func__, opp->supplies[i].u_volt_min,
  				opp->supplies[i].u_volt_max);
  			return false;
  		}
7d34d56ef   Viresh Kumar   PM / OPP: Disable...
1377
1378
1379
1380
  	}
  
  	return true;
  }
6c591eec6   Saravana Kannan   OPP: Add helpers ...
1381
1382
1383
1384
  int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2)
  {
  	if (opp1->rate != opp2->rate)
  		return opp1->rate < opp2->rate ? -1 : 1;
6d3f922c4   Georgi Djakov   opp: Add support ...
1385
1386
1387
  	if (opp1->bandwidth && opp2->bandwidth &&
  	    opp1->bandwidth[0].peak != opp2->bandwidth[0].peak)
  		return opp1->bandwidth[0].peak < opp2->bandwidth[0].peak ? -1 : 1;
6c591eec6   Saravana Kannan   OPP: Add helpers ...
1388
1389
1390
1391
  	if (opp1->level != opp2->level)
  		return opp1->level < opp2->level ? -1 : 1;
  	return 0;
  }
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1392
1393
1394
  static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
  			     struct opp_table *opp_table,
  			     struct list_head **head)
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1395
1396
  {
  	struct dev_pm_opp *opp;
6c591eec6   Saravana Kannan   OPP: Add helpers ...
1397
  	int opp_cmp;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1398
1399
1400
1401
1402
  
  	/*
  	 * Insert new OPP in order of increasing frequency and discard if
  	 * already present.
  	 *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1403
  	 * Need to use &opp_table->opp_list in the condition part of the 'for'
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1404
1405
1406
  	 * loop, don't replace it with head otherwise it will become an infinite
  	 * loop.
  	 */
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1407
  	list_for_each_entry(opp, &opp_table->opp_list, node) {
6c591eec6   Saravana Kannan   OPP: Add helpers ...
1408
1409
  		opp_cmp = _opp_compare_key(new_opp, opp);
  		if (opp_cmp > 0) {
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1410
  			*head = &opp->node;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1411
1412
  			continue;
  		}
6c591eec6   Saravana Kannan   OPP: Add helpers ...
1413
  		if (opp_cmp < 0)
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1414
  			return 0;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1415
1416
  
  		/* Duplicate OPPs */
064416586   Viresh Kumar   PM / OPP: Add OPP...
1417
1418
  		dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d
  ",
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1419
1420
1421
  			 __func__, opp->rate, opp->supplies[0].u_volt,
  			 opp->available, new_opp->rate,
  			 new_opp->supplies[0].u_volt, new_opp->available);
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1422

dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1423
  		/* Should we compare voltages for all regulators here ? */
a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
  		return opp->available &&
  		       new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
  	}
  
  	return 0;
  }
  
  /*
   * Returns:
   * 0: On success. And appropriate error message for duplicate OPPs.
   * -EBUSY: For OPP with same freq/volt and is available. The callers of
   *  _opp_add() must return 0 if they receive -EBUSY from it. This is to make
   *  sure we don't print error messages unnecessarily if different parts of
   *  kernel try to initialize the OPP table.
   * -EEXIST: For OPP with same freq but different volt or is unavailable. This
   *  should be considered an error by the callers of _opp_add().
   */
  int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  	     struct opp_table *opp_table, bool rate_not_available)
  {
  	struct list_head *head;
  	int ret;
  
  	mutex_lock(&opp_table->lock);
  	head = &opp_table->opp_list;
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1449

a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1450
1451
1452
1453
1454
1455
  	if (likely(!rate_not_available)) {
  		ret = _opp_is_duplicate(dev, new_opp, opp_table, &head);
  		if (ret) {
  			mutex_unlock(&opp_table->lock);
  			return ret;
  		}
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1456
  	}
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1457
  	list_add(&new_opp->node, head);
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
1458
1459
1460
  	mutex_unlock(&opp_table->lock);
  
  	new_opp->opp_table = opp_table;
7034764a1   Viresh Kumar   PM / OPP: Add 'st...
1461
  	kref_init(&new_opp->kref);
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1462

a2dea4cb9   Greg Kroah-Hartman   opp: no need to c...
1463
  	opp_debug_create_one(new_opp, opp_table);
deaa51465   Viresh Kumar   PM / OPP: Add deb...
1464

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1465
  	if (!_opp_supported_by_regulators(new_opp, opp_table)) {
7d34d56ef   Viresh Kumar   PM / OPP: Disable...
1466
1467
1468
1469
1470
  		new_opp->available = false;
  		dev_warn(dev, "%s: OPP not supported by regulators (%lu)
  ",
  			 __func__, new_opp->rate);
  	}
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1471
1472
  	return 0;
  }
737002b5d   Viresh Kumar   PM / OPP: Relocat...
1473
  /**
b64b9c3f9   Viresh Kumar   PM / OPP: Rename ...
1474
   * _opp_add_v1() - Allocate a OPP based on v1 bindings.
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1475
   * @opp_table:	OPP table
984f16c84   Nishanth Menon   PM / OPP: Update ...
1476
1477
1478
1479
1480
   * @dev:	device for which we do this operation
   * @freq:	Frequency in Hz for this OPP
   * @u_volt:	Voltage in uVolts for this OPP
   * @dynamic:	Dynamically added OPPs.
   *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1481
   * This function adds an opp definition to the opp table and returns status.
984f16c84   Nishanth Menon   PM / OPP: Update ...
1482
1483
1484
   * The opp is made available by default and it can be controlled using
   * dev_pm_opp_enable/disable functions and may be removed by dev_pm_opp_remove.
   *
8f8d37b25   Viresh Kumar   PM / OPP: Prefix ...
1485
1486
   * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
   * and freed by dev_pm_opp_of_remove_table.
984f16c84   Nishanth Menon   PM / OPP: Update ...
1487
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
1488
1489
1490
1491
1492
1493
1494
   * Return:
   * 0		On success OR
   *		Duplicate OPPs (both freq and volt are same) and opp->available
   * -EEXIST	Freq are same and volt are different OR
   *		Duplicate OPPs (both freq and volt are same) and !opp->available
   * -ENOMEM	Memory allocation failure
   */
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1495
1496
  int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
  		unsigned long freq, long u_volt, bool dynamic)
e1f60b292   Nishanth Menon   PM: Introduce lib...
1497
  {
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1498
  	struct dev_pm_opp *new_opp;
50f8cfbd5   Viresh Kumar   PM / OPP: Parse c...
1499
  	unsigned long tol;
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
1500
  	int ret;
e1f60b292   Nishanth Menon   PM: Introduce lib...
1501

8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1502
1503
1504
  	new_opp = _opp_allocate(opp_table);
  	if (!new_opp)
  		return -ENOMEM;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1505

a7470db6f   Viresh Kumar   PM / OPP don't ma...
1506
  	/* populate the opp table */
a7470db6f   Viresh Kumar   PM / OPP don't ma...
1507
  	new_opp->rate = freq;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1508
  	tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1509
1510
1511
  	new_opp->supplies[0].u_volt = u_volt;
  	new_opp->supplies[0].u_volt_min = u_volt - tol;
  	new_opp->supplies[0].u_volt_max = u_volt + tol;
a7470db6f   Viresh Kumar   PM / OPP don't ma...
1512
  	new_opp->available = true;
23dacf6d2   Viresh Kumar   PM / OPP: Break _...
1513
  	new_opp->dynamic = dynamic;
a7470db6f   Viresh Kumar   PM / OPP don't ma...
1514

a1e8c1360   Viresh Kumar   PM / OPP: "opp-hz...
1515
  	ret = _opp_add(dev, new_opp, opp_table, false);
7f8538eba   Viresh Kumar   PM / OPP: Fix mem...
1516
1517
1518
1519
  	if (ret) {
  		/* Don't return error for duplicate OPPs */
  		if (ret == -EBUSY)
  			ret = 0;
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
1520
  		goto free_opp;
7f8538eba   Viresh Kumar   PM / OPP: Fix mem...
1521
  	}
64ce85457   Chander Kashyap   PM / OPP: discard...
1522

03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
1523
1524
1525
1526
  	/*
  	 * Notify the changes in the availability of the operable
  	 * frequency/voltage list.
  	 */
052c6f191   Viresh Kumar   PM / OPP: Move aw...
1527
  	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
1528
  	return 0;
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
1529
1530
  
  free_opp:
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
1531
  	_opp_free(new_opp);
6ce4184d0   Viresh Kumar   PM / OPP: do erro...
1532
  	return ret;
e1f60b292   Nishanth Menon   PM: Introduce lib...
1533
  }
38393409d   Viresh Kumar   PM / OPP mark OPP...
1534

274659029   Viresh Kumar   PM / OPP: Add sup...
1535
  /**
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1536
1537
1538
1539
1540
1541
1542
1543
1544
   * dev_pm_opp_set_supported_hw() - Set supported platforms
   * @dev: Device for which supported-hw has to be set.
   * @versions: Array of hierarchy of versions to match.
   * @count: Number of elements in the array.
   *
   * This is required only for the V2 bindings, and it enables a platform to
   * specify the hierarchy of versions it supports. OPP layer will then enable
   * OPPs, which are available for those versions, based on its 'opp-supported-hw'
   * property.
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1545
   */
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1546
1547
  struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
  			const u32 *versions, unsigned int count)
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1548
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1549
  	struct opp_table *opp_table;
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1550

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1551
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1552
1553
  	if (IS_ERR(opp_table))
  		return opp_table;
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1554

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1555
1556
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1557

25419de1b   Viresh Kumar   PM / OPP: Fix sha...
1558
1559
1560
  	/* Another CPU that shares the OPP table has set the property ? */
  	if (opp_table->supported_hw)
  		return opp_table;
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1561

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1562
  	opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1563
  					GFP_KERNEL);
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1564
  	if (!opp_table->supported_hw) {
25419de1b   Viresh Kumar   PM / OPP: Fix sha...
1565
1566
  		dev_pm_opp_put_opp_table(opp_table);
  		return ERR_PTR(-ENOMEM);
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1567
  	}
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1568
  	opp_table->supported_hw_count = count;
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1569
1570
  
  	return opp_table;
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1571
1572
1573
1574
1575
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
  
  /**
   * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1576
   * @opp_table: OPP table returned by dev_pm_opp_set_supported_hw().
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1577
1578
   *
   * This is required only for the V2 bindings, and is called for a matching
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1579
   * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1580
   * will not be freed.
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1581
   */
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1582
  void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1583
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1584
1585
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1586

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1587
1588
1589
  	kfree(opp_table->supported_hw);
  	opp_table->supported_hw = NULL;
  	opp_table->supported_hw_count = 0;
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1590

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1591
  	dev_pm_opp_put_opp_table(opp_table);
7de36b0aa   Viresh Kumar   PM / OPP: Parse '...
1592
1593
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1594
1595
  /**
   * dev_pm_opp_set_prop_name() - Set prop-extn name
a5da64477   Viresh Kumar   PM / OPP: Fix inc...
1596
   * @dev: Device for which the prop-name has to be set.
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1597
1598
1599
1600
1601
1602
   * @name: name to postfix to properties.
   *
   * This is required only for the V2 bindings, and it enables a platform to
   * specify the extn to be used for certain property names. The properties to
   * which the extension will apply are opp-microvolt and opp-microamp. OPP core
   * should postfix the property name with -<name> while looking for them.
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1603
   */
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1604
  struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1605
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1606
  	struct opp_table *opp_table;
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1607

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1608
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1609
1610
  	if (IS_ERR(opp_table))
  		return opp_table;
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1611

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1612
1613
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1614

878ec1a9f   Viresh Kumar   PM / OPP: Fix sha...
1615
1616
1617
  	/* Another CPU that shares the OPP table has set the property ? */
  	if (opp_table->prop_name)
  		return opp_table;
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1618

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1619
1620
  	opp_table->prop_name = kstrdup(name, GFP_KERNEL);
  	if (!opp_table->prop_name) {
878ec1a9f   Viresh Kumar   PM / OPP: Fix sha...
1621
1622
  		dev_pm_opp_put_opp_table(opp_table);
  		return ERR_PTR(-ENOMEM);
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1623
  	}
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1624
  	return opp_table;
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1625
1626
1627
1628
1629
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
  
  /**
   * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1630
   * @opp_table: OPP table returned by dev_pm_opp_set_prop_name().
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1631
1632
   *
   * This is required only for the V2 bindings, and is called for a matching
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1633
   * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1634
   * will not be freed.
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1635
   */
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1636
  void dev_pm_opp_put_prop_name(struct opp_table *opp_table)
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1637
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1638
1639
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1640

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1641
1642
  	kfree(opp_table->prop_name);
  	opp_table->prop_name = NULL;
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1643

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1644
  	dev_pm_opp_put_opp_table(opp_table);
01fb4d3c3   Viresh Kumar   PM / OPP: Parse '...
1645
1646
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
947355850   Viresh Kumar   PM / OPP: Separat...
1647
1648
1649
1650
  static int _allocate_set_opp_data(struct opp_table *opp_table)
  {
  	struct dev_pm_set_opp_data *data;
  	int len, count = opp_table->regulator_count;
90e3577b5   Viresh Kumar   OPP: Use opp_tabl...
1651
  	if (WARN_ON(!opp_table->regulators))
947355850   Viresh Kumar   PM / OPP: Separat...
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
  		return -EINVAL;
  
  	/* space for set_opp_data */
  	len = sizeof(*data);
  
  	/* space for old_opp.supplies and new_opp.supplies */
  	len += 2 * sizeof(struct dev_pm_opp_supply) * count;
  
  	data = kzalloc(len, GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	data->old_opp.supplies = (void *)(data + 1);
  	data->new_opp.supplies = data->old_opp.supplies + count;
  
  	opp_table->set_opp_data = data;
  
  	return 0;
  }
  
  static void _free_set_opp_data(struct opp_table *opp_table)
  {
  	kfree(opp_table->set_opp_data);
  	opp_table->set_opp_data = NULL;
  }
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1677
  /**
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1678
   * dev_pm_opp_set_regulators() - Set regulator names for the device
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1679
   * @dev: Device for which regulator name is being set.
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1680
1681
   * @names: Array of pointers to the names of the regulator.
   * @count: Number of regulators.
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1682
1683
   *
   * In order to support OPP switching, OPP layer needs to know the name of the
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1684
1685
   * device's regulators, as the core would be required to switch voltages as
   * well.
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1686
1687
   *
   * This must be called before any OPPs are initialized for the device.
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1688
   */
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1689
1690
1691
  struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
  					    const char * const names[],
  					    unsigned int count)
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1692
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1693
  	struct opp_table *opp_table;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1694
  	struct regulator *reg;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1695
  	int ret, i;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1696

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1697
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1698
1699
  	if (IS_ERR(opp_table))
  		return opp_table;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1700
1701
  
  	/* This should be called before OPPs are initialized */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1702
  	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1703
1704
1705
  		ret = -EBUSY;
  		goto err;
  	}
779b783cf   Viresh Kumar   PM / OPP: Fix sha...
1706
1707
1708
  	/* Another CPU that shares the OPP table has set the regulators ? */
  	if (opp_table->regulators)
  		return opp_table;
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1709
1710
1711
1712
1713
1714
  
  	opp_table->regulators = kmalloc_array(count,
  					      sizeof(*opp_table->regulators),
  					      GFP_KERNEL);
  	if (!opp_table->regulators) {
  		ret = -ENOMEM;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1715
1716
  		goto err;
  	}
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
  	for (i = 0; i < count; i++) {
  		reg = regulator_get_optional(dev, names[i]);
  		if (IS_ERR(reg)) {
  			ret = PTR_ERR(reg);
  			if (ret != -EPROBE_DEFER)
  				dev_err(dev, "%s: no regulator (%s) found: %d
  ",
  					__func__, names[i], ret);
  			goto free_regulators;
  		}
  
  		opp_table->regulators[i] = reg;
  	}
  
  	opp_table->regulator_count = count;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1732

947355850   Viresh Kumar   PM / OPP: Separat...
1733
1734
1735
1736
  	/* Allocate block only once to pass to set_opp() routines */
  	ret = _allocate_set_opp_data(opp_table);
  	if (ret)
  		goto free_regulators;
91291d9ad   Stephen Boyd   PM / OPP: Pass op...
1737
  	return opp_table;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1738

dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1739
  free_regulators:
24957db10   Marek Szyprowski   opp: core: Revert...
1740
1741
  	while (i != 0)
  		regulator_put(opp_table->regulators[--i]);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1742
1743
1744
  
  	kfree(opp_table->regulators);
  	opp_table->regulators = NULL;
46f48aca2   Viresh Kumar   OPP: Fix missing ...
1745
  	opp_table->regulator_count = -1;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1746
  err:
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1747
  	dev_pm_opp_put_opp_table(opp_table);
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1748

91291d9ad   Stephen Boyd   PM / OPP: Pass op...
1749
  	return ERR_PTR(ret);
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1750
  }
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1751
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1752
1753
  
  /**
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1754
1755
   * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
   * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1756
   */
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1757
  void dev_pm_opp_put_regulators(struct opp_table *opp_table)
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1758
  {
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1759
  	int i;
779b783cf   Viresh Kumar   PM / OPP: Fix sha...
1760
1761
  	if (!opp_table->regulators)
  		goto put_opp_table;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1762

2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
1763
1764
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1765

72f80ce4e   Viresh Kumar   opp: Rename regul...
1766
  	if (opp_table->enabled) {
8d45719ca   Kamil Konieczny   opp: core: add re...
1767
1768
  		for (i = opp_table->regulator_count - 1; i >= 0; i--)
  			regulator_disable(opp_table->regulators[i]);
8d45719ca   Kamil Konieczny   opp: core: add re...
1769
  	}
24957db10   Marek Szyprowski   opp: core: Revert...
1770
  	for (i = opp_table->regulator_count - 1; i >= 0; i--)
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1771
  		regulator_put(opp_table->regulators[i]);
947355850   Viresh Kumar   PM / OPP: Separat...
1772
  	_free_set_opp_data(opp_table);
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1773
1774
  	kfree(opp_table->regulators);
  	opp_table->regulators = NULL;
46f48aca2   Viresh Kumar   OPP: Fix missing ...
1775
  	opp_table->regulator_count = -1;
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1776

779b783cf   Viresh Kumar   PM / OPP: Fix sha...
1777
  put_opp_table:
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1778
  	dev_pm_opp_put_opp_table(opp_table);
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1779
  }
dfbe4678d   Viresh Kumar   PM / OPP: Add inf...
1780
  EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
9f8ea969d   Viresh Kumar   PM / OPP: get/put...
1781

38393409d   Viresh Kumar   PM / OPP mark OPP...
1782
  /**
829a4e8c0   Viresh Kumar   PM / OPP: Add dev...
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
   * dev_pm_opp_set_clkname() - Set clk name for the device
   * @dev: Device for which clk name is being set.
   * @name: Clk name.
   *
   * In order to support OPP switching, OPP layer needs to get pointer to the
   * clock for the device. Simple cases work fine without using this routine (i.e.
   * by passing connection-id as NULL), but for a device with multiple clocks
   * available, the OPP core needs to know the exact name of the clk to use.
   *
   * This must be called before any OPPs are initialized for the device.
   */
  struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
  {
  	struct opp_table *opp_table;
  	int ret;
  
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1800
1801
  	if (IS_ERR(opp_table))
  		return opp_table;
829a4e8c0   Viresh Kumar   PM / OPP: Add dev...
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
  
  	/* This should be called before OPPs are initialized */
  	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
  		ret = -EBUSY;
  		goto err;
  	}
  
  	/* Already have default clk set, free it */
  	if (!IS_ERR(opp_table->clk))
  		clk_put(opp_table->clk);
  
  	/* Find clk for the device */
  	opp_table->clk = clk_get(dev, name);
  	if (IS_ERR(opp_table->clk)) {
  		ret = PTR_ERR(opp_table->clk);
  		if (ret != -EPROBE_DEFER) {
  			dev_err(dev, "%s: Couldn't find clock: %d
  ", __func__,
  				ret);
  		}
  		goto err;
  	}
  
  	return opp_table;
  
  err:
  	dev_pm_opp_put_opp_table(opp_table);
  
  	return ERR_PTR(ret);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_set_clkname);
  
  /**
   * dev_pm_opp_put_clkname() - Releases resources blocked for clk.
   * @opp_table: OPP table returned from dev_pm_opp_set_clkname().
   */
  void dev_pm_opp_put_clkname(struct opp_table *opp_table)
  {
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
  
  	clk_put(opp_table->clk);
  	opp_table->clk = ERR_PTR(-EINVAL);
  
  	dev_pm_opp_put_opp_table(opp_table);
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname);
  
  /**
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1851
1852
1853
1854
1855
1856
1857
1858
   * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
   * @dev: Device for which the helper is getting registered.
   * @set_opp: Custom set OPP helper.
   *
   * This is useful to support complex platforms (like platforms with multiple
   * regulators per device), instead of the generic OPP set rate helper.
   *
   * This must be called before any OPPs are initialized for the device.
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1859
   */
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1860
  struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1861
1862
1863
  			int (*set_opp)(struct dev_pm_set_opp_data *data))
  {
  	struct opp_table *opp_table;
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1864
1865
  
  	if (!set_opp)
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1866
  		return ERR_PTR(-EINVAL);
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1867

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1868
  	opp_table = dev_pm_opp_get_opp_table(dev);
47efcbcb3   Viresh Kumar   opp: Fix early ex...
1869
  	if (IS_ERR(opp_table))
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1870
  		return opp_table;
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1871
1872
1873
  
  	/* This should be called before OPPs are initialized */
  	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
5019acc69   Viresh Kumar   PM / OPP: Fix sha...
1874
1875
  		dev_pm_opp_put_opp_table(opp_table);
  		return ERR_PTR(-EBUSY);
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1876
  	}
5019acc69   Viresh Kumar   PM / OPP: Fix sha...
1877
1878
1879
  	/* Another CPU that shares the OPP table has set the helper ? */
  	if (!opp_table->set_opp)
  		opp_table->set_opp = set_opp;
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1880

fa30184d1   Viresh Kumar   PM / OPP: Return ...
1881
  	return opp_table;
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1882
1883
1884
1885
  }
  EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
  
  /**
604a7aeb4   Viresh Kumar   PM / OPP: Rename ...
1886
   * dev_pm_opp_unregister_set_opp_helper() - Releases resources blocked for
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1887
   *					   set_opp helper
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1888
   * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper().
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1889
   *
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1890
   * Release resources blocked for platform specific set_opp helper.
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1891
   */
604a7aeb4   Viresh Kumar   PM / OPP: Rename ...
1892
  void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table)
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1893
  {
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1894
1895
1896
1897
  	/* Make sure there are no concurrent readers while updating opp_table */
  	WARN_ON(!list_empty(&opp_table->opp_list));
  
  	opp_table->set_opp = NULL;
fa30184d1   Viresh Kumar   PM / OPP: Return ...
1898
  	dev_pm_opp_put_opp_table(opp_table);
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1899
  }
604a7aeb4   Viresh Kumar   PM / OPP: Rename ...
1900
  EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper);
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1901

6319aee10   Viresh Kumar   opp: Attach genpd...
1902
1903
1904
  static void _opp_detach_genpd(struct opp_table *opp_table)
  {
  	int index;
cb60e9602   Viresh Kumar   opp: Prevent memo...
1905
1906
  	if (!opp_table->genpd_virt_devs)
  		return;
6319aee10   Viresh Kumar   opp: Attach genpd...
1907
1908
1909
1910
1911
1912
1913
  	for (index = 0; index < opp_table->required_opp_count; index++) {
  		if (!opp_table->genpd_virt_devs[index])
  			continue;
  
  		dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false);
  		opp_table->genpd_virt_devs[index] = NULL;
  	}
c0ab9e081   Viresh Kumar   opp: Allocate gen...
1914
1915
1916
  
  	kfree(opp_table->genpd_virt_devs);
  	opp_table->genpd_virt_devs = NULL;
6319aee10   Viresh Kumar   opp: Attach genpd...
1917
  }
4dab160eb   Viresh Kumar   PM / OPP: Allow p...
1918
  /**
6319aee10   Viresh Kumar   opp: Attach genpd...
1919
1920
1921
   * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
   * @dev: Consumer device for which the genpd is getting attached.
   * @names: Null terminated array of pointers containing names of genpd to attach.
17a8f868a   Viresh Kumar   opp: Return genpd...
1922
   * @virt_devs: Pointer to return the array of virtual devices.
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1923
1924
1925
1926
1927
   *
   * Multiple generic power domains for a device are supported with the help of
   * virtual genpd devices, which are created for each consumer device - genpd
   * pair. These are the device structures which are attached to the power domain
   * and are required by the OPP core to set the performance state of the genpd.
6319aee10   Viresh Kumar   opp: Attach genpd...
1928
1929
   * The same API also works for the case where single genpd is available and so
   * we don't need to support that separately.
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1930
1931
   *
   * This helper will normally be called by the consumer driver of the device
6319aee10   Viresh Kumar   opp: Attach genpd...
1932
   * "dev", as only that has details of the genpd names.
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1933
   *
6319aee10   Viresh Kumar   opp: Attach genpd...
1934
1935
   * This helper needs to be called once with a list of all genpd to attach.
   * Otherwise the original device structure will be used instead by the OPP core.
baea35e4d   Viresh Kumar   opp: Not all powe...
1936
1937
1938
   *
   * The order of entries in the names array must match the order in which
   * "required-opps" are added in DT.
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1939
   */
17a8f868a   Viresh Kumar   opp: Return genpd...
1940
1941
  struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
  		const char **names, struct device ***virt_devs)
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1942
1943
  {
  	struct opp_table *opp_table;
6319aee10   Viresh Kumar   opp: Attach genpd...
1944
  	struct device *virt_dev;
baea35e4d   Viresh Kumar   opp: Not all powe...
1945
  	int index = 0, ret = -EINVAL;
6319aee10   Viresh Kumar   opp: Attach genpd...
1946
  	const char **name = names;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1947
1948
  
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
1949
1950
  	if (IS_ERR(opp_table))
  		return opp_table;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1951

cb60e9602   Viresh Kumar   opp: Prevent memo...
1952
1953
  	if (opp_table->genpd_virt_devs)
  		return opp_table;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1954

6319aee10   Viresh Kumar   opp: Attach genpd...
1955
1956
1957
1958
1959
1960
1961
1962
1963
  	/*
  	 * If the genpd's OPP table isn't already initialized, parsing of the
  	 * required-opps fail for dev. We should retry this after genpd's OPP
  	 * table is added.
  	 */
  	if (!opp_table->required_opp_count) {
  		ret = -EPROBE_DEFER;
  		goto put_table;
  	}
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1964
  	mutex_lock(&opp_table->genpd_virt_dev_lock);
c0ab9e081   Viresh Kumar   opp: Allocate gen...
1965
1966
1967
1968
1969
  	opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count,
  					     sizeof(*opp_table->genpd_virt_devs),
  					     GFP_KERNEL);
  	if (!opp_table->genpd_virt_devs)
  		goto unlock;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1970

6319aee10   Viresh Kumar   opp: Attach genpd...
1971
  	while (*name) {
6319aee10   Viresh Kumar   opp: Attach genpd...
1972
1973
1974
1975
1976
1977
  		if (index >= opp_table->required_opp_count) {
  			dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)
  ",
  				*name, opp_table->required_opp_count, index);
  			goto err;
  		}
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1978

6319aee10   Viresh Kumar   opp: Attach genpd...
1979
1980
1981
1982
1983
1984
1985
1986
1987
  		virt_dev = dev_pm_domain_attach_by_name(dev, *name);
  		if (IS_ERR(virt_dev)) {
  			ret = PTR_ERR(virt_dev);
  			dev_err(dev, "Couldn't attach to pm_domain: %d
  ", ret);
  			goto err;
  		}
  
  		opp_table->genpd_virt_devs[index] = virt_dev;
baea35e4d   Viresh Kumar   opp: Not all powe...
1988
  		index++;
6319aee10   Viresh Kumar   opp: Attach genpd...
1989
  		name++;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1990
  	}
17a8f868a   Viresh Kumar   opp: Return genpd...
1991
1992
  	if (virt_devs)
  		*virt_devs = opp_table->genpd_virt_devs;
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
1993
1994
1995
  	mutex_unlock(&opp_table->genpd_virt_dev_lock);
  
  	return opp_table;
6319aee10   Viresh Kumar   opp: Attach genpd...
1996
1997
1998
  
  err:
  	_opp_detach_genpd(opp_table);
c0ab9e081   Viresh Kumar   opp: Allocate gen...
1999
  unlock:
6319aee10   Viresh Kumar   opp: Attach genpd...
2000
2001
2002
2003
2004
2005
  	mutex_unlock(&opp_table->genpd_virt_dev_lock);
  
  put_table:
  	dev_pm_opp_put_opp_table(opp_table);
  
  	return ERR_PTR(ret);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2006
  }
6319aee10   Viresh Kumar   opp: Attach genpd...
2007
  EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2008
2009
  
  /**
6319aee10   Viresh Kumar   opp: Attach genpd...
2010
2011
   * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device.
   * @opp_table: OPP table returned by dev_pm_opp_attach_genpd().
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2012
   *
6319aee10   Viresh Kumar   opp: Attach genpd...
2013
2014
   * This detaches the genpd(s), resets the virtual device pointers, and puts the
   * OPP table.
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2015
   */
6319aee10   Viresh Kumar   opp: Attach genpd...
2016
  void dev_pm_opp_detach_genpd(struct opp_table *opp_table)
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2017
  {
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2018
2019
2020
2021
2022
  	/*
  	 * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting
  	 * used in parallel.
  	 */
  	mutex_lock(&opp_table->genpd_virt_dev_lock);
6319aee10   Viresh Kumar   opp: Attach genpd...
2023
  	_opp_detach_genpd(opp_table);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2024
  	mutex_unlock(&opp_table->genpd_virt_dev_lock);
6319aee10   Viresh Kumar   opp: Attach genpd...
2025
  	dev_pm_opp_put_opp_table(opp_table);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2026
  }
6319aee10   Viresh Kumar   opp: Attach genpd...
2027
  EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd);
4f018bc0e   Viresh Kumar   OPP: Add dev_pm_o...
2028
2029
  
  /**
c8a59103e   Viresh Kumar   OPP: Add dev_pm_o...
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
   * dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
   * @src_table: OPP table which has dst_table as one of its required OPP table.
   * @dst_table: Required OPP table of the src_table.
   * @pstate: Current performance state of the src_table.
   *
   * This Returns pstate of the OPP (present in @dst_table) pointed out by the
   * "required-opps" property of the OPP (present in @src_table) which has
   * performance state set to @pstate.
   *
   * Return: Zero or positive performance state on success, otherwise negative
   * value on errors.
   */
  int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
  				       struct opp_table *dst_table,
  				       unsigned int pstate)
  {
  	struct dev_pm_opp *opp;
  	int dest_pstate = -EINVAL;
  	int i;
c8a59103e   Viresh Kumar   OPP: Add dev_pm_o...
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
  	/*
  	 * Normally the src_table will have the "required_opps" property set to
  	 * point to one of the OPPs in the dst_table, but in some cases the
  	 * genpd and its master have one to one mapping of performance states
  	 * and so none of them have the "required-opps" property set. Return the
  	 * pstate of the src_table as it is in such cases.
  	 */
  	if (!src_table->required_opp_count)
  		return pstate;
  
  	for (i = 0; i < src_table->required_opp_count; i++) {
  		if (src_table->required_opp_tables[i]->np == dst_table->np)
  			break;
  	}
  
  	if (unlikely(i == src_table->required_opp_count)) {
  		pr_err("%s: Couldn't find matching OPP table (%p: %p)
  ",
  		       __func__, src_table, dst_table);
  		return -EINVAL;
  	}
  
  	mutex_lock(&src_table->lock);
  
  	list_for_each_entry(opp, &src_table->opp_list, node) {
  		if (opp->pstate == pstate) {
  			dest_pstate = opp->required_opps[i]->pstate;
  			goto unlock;
  		}
  	}
  
  	pr_err("%s: Couldn't find matching OPP (%p: %p)
  ", __func__, src_table,
  	       dst_table);
  
  unlock:
  	mutex_unlock(&src_table->lock);
  
  	return dest_pstate;
  }
  
  /**
38393409d   Viresh Kumar   PM / OPP mark OPP...
2091
2092
2093
2094
2095
   * dev_pm_opp_add()  - Add an OPP table from a table definitions
   * @dev:	device for which we do this operation
   * @freq:	Frequency in Hz for this OPP
   * @u_volt:	Voltage in uVolts for this OPP
   *
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2096
   * This function adds an opp definition to the opp table and returns status.
38393409d   Viresh Kumar   PM / OPP mark OPP...
2097
2098
2099
   * The opp is made available by default and it can be controlled using
   * dev_pm_opp_enable/disable functions.
   *
38393409d   Viresh Kumar   PM / OPP mark OPP...
2100
   * Return:
984f16c84   Nishanth Menon   PM / OPP: Update ...
2101
   * 0		On success OR
38393409d   Viresh Kumar   PM / OPP mark OPP...
2102
   *		Duplicate OPPs (both freq and volt are same) and opp->available
984f16c84   Nishanth Menon   PM / OPP: Update ...
2103
   * -EEXIST	Freq are same and volt are different OR
38393409d   Viresh Kumar   PM / OPP mark OPP...
2104
   *		Duplicate OPPs (both freq and volt are same) and !opp->available
984f16c84   Nishanth Menon   PM / OPP: Update ...
2105
   * -ENOMEM	Memory allocation failure
38393409d   Viresh Kumar   PM / OPP mark OPP...
2106
2107
2108
   */
  int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
  {
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
2109
2110
  	struct opp_table *opp_table;
  	int ret;
b83c1899a   Viresh Kumar   PM / OPP: Use dev...
2111
  	opp_table = dev_pm_opp_get_opp_table(dev);
dd461cd91   Stephan Gerhold   opp: Allow dev_pm...
2112
2113
  	if (IS_ERR(opp_table))
  		return PTR_ERR(opp_table);
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
2114

46f48aca2   Viresh Kumar   OPP: Fix missing ...
2115
2116
  	/* Fix regulator count for dynamic OPPs */
  	opp_table->regulator_count = 1;
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
2117
  	ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
0ad8c6239   Viresh Kumar   OPP: Don't take O...
2118
2119
  	if (ret)
  		dev_pm_opp_put_opp_table(opp_table);
8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
2120

8cd2f6e8f   Viresh Kumar   PM / OPP: Don't a...
2121
  	return ret;
38393409d   Viresh Kumar   PM / OPP mark OPP...
2122
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2123
  EXPORT_SYMBOL_GPL(dev_pm_opp_add);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2124

984f16c84   Nishanth Menon   PM / OPP: Update ...
2125
  /**
327854c87   Nishanth Menon   PM / OPP: Ensure ...
2126
   * _opp_set_availability() - helper to set the availability of an opp
e1f60b292   Nishanth Menon   PM: Introduce lib...
2127
2128
2129
2130
   * @dev:		device for which we do this operation
   * @freq:		OPP frequency to modify availability
   * @availability_req:	availability status requested for this opp
   *
052c6f191   Viresh Kumar   PM / OPP: Move aw...
2131
2132
   * Set the availability of an OPP, opp_{enable,disable} share a common logic
   * which is isolated here.
e1f60b292   Nishanth Menon   PM: Introduce lib...
2133
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
2134
   * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
e1a2d49cd   Stephen Boyd   PM / OPP: Fix typ...
2135
   * copy operation, returns 0 if no modification was done OR modification was
e1f60b292   Nishanth Menon   PM: Introduce lib...
2136
   * successful.
e1f60b292   Nishanth Menon   PM: Introduce lib...
2137
   */
327854c87   Nishanth Menon   PM / OPP: Ensure ...
2138
2139
  static int _opp_set_availability(struct device *dev, unsigned long freq,
  				 bool availability_req)
e1f60b292   Nishanth Menon   PM: Introduce lib...
2140
  {
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2141
  	struct opp_table *opp_table;
a7f3987ea   Viresh Kumar   PM / OPP: Simplif...
2142
  	struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2143
  	int r = 0;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2144
2145
2146
2147
  	/* Find the opp_table */
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		r = PTR_ERR(opp_table);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2148
2149
  		dev_warn(dev, "%s: Device OPP not found (%d)
  ", __func__, r);
a7f3987ea   Viresh Kumar   PM / OPP: Simplif...
2150
  		return r;
e1f60b292   Nishanth Menon   PM: Introduce lib...
2151
  	}
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
2152
  	mutex_lock(&opp_table->lock);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2153
  	/* Do we have the frequency? */
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2154
  	list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
e1f60b292   Nishanth Menon   PM: Introduce lib...
2155
2156
2157
2158
2159
  		if (tmp_opp->rate == freq) {
  			opp = tmp_opp;
  			break;
  		}
  	}
37a73ec0c   Viresh Kumar   PM / OPP: Add per...
2160

e1f60b292   Nishanth Menon   PM: Introduce lib...
2161
2162
2163
2164
2165
2166
2167
2168
  	if (IS_ERR(opp)) {
  		r = PTR_ERR(opp);
  		goto unlock;
  	}
  
  	/* Is update really needed? */
  	if (opp->available == availability_req)
  		goto unlock;
e1f60b292   Nishanth Menon   PM: Introduce lib...
2169

a7f3987ea   Viresh Kumar   PM / OPP: Simplif...
2170
  	opp->available = availability_req;
e1f60b292   Nishanth Menon   PM: Introduce lib...
2171

e4d8ae001   Viresh Kumar   PM / OPP: Call no...
2172
2173
  	dev_pm_opp_get(opp);
  	mutex_unlock(&opp_table->lock);
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2174
2175
  	/* Notify the change of the OPP availability */
  	if (availability_req)
052c6f191   Viresh Kumar   PM / OPP: Move aw...
2176
  		blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE,
a7f3987ea   Viresh Kumar   PM / OPP: Simplif...
2177
  					     opp);
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2178
  	else
052c6f191   Viresh Kumar   PM / OPP: Move aw...
2179
  		blocking_notifier_call_chain(&opp_table->head,
a7f3987ea   Viresh Kumar   PM / OPP: Simplif...
2180
  					     OPP_EVENT_DISABLE, opp);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2181

e4d8ae001   Viresh Kumar   PM / OPP: Call no...
2182
2183
  	dev_pm_opp_put(opp);
  	goto put_table;
e1f60b292   Nishanth Menon   PM: Introduce lib...
2184
  unlock:
5b650b388   Viresh Kumar   PM / OPP: Take kr...
2185
  	mutex_unlock(&opp_table->lock);
e4d8ae001   Viresh Kumar   PM / OPP: Call no...
2186
  put_table:
5b650b388   Viresh Kumar   PM / OPP: Take kr...
2187
  	dev_pm_opp_put_opp_table(opp_table);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2188
2189
2190
2191
  	return r;
  }
  
  /**
25cb20a21   Stephen Boyd   PM / OPP: Support...
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
   * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP
   * @dev:		device for which we do this operation
   * @freq:		OPP frequency to adjust voltage of
   * @u_volt:		new OPP target voltage
   * @u_volt_min:		new OPP min voltage
   * @u_volt_max:		new OPP max voltage
   *
   * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
   * copy operation, returns 0 if no modifcation was done OR modification was
   * successful.
   */
  int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
  			      unsigned long u_volt, unsigned long u_volt_min,
  			      unsigned long u_volt_max)
  
  {
  	struct opp_table *opp_table;
  	struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
  	int r = 0;
  
  	/* Find the opp_table */
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		r = PTR_ERR(opp_table);
  		dev_warn(dev, "%s: Device OPP not found (%d)
  ", __func__, r);
  		return r;
  	}
  
  	mutex_lock(&opp_table->lock);
  
  	/* Do we have the frequency? */
  	list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
  		if (tmp_opp->rate == freq) {
  			opp = tmp_opp;
  			break;
  		}
  	}
  
  	if (IS_ERR(opp)) {
  		r = PTR_ERR(opp);
  		goto adjust_unlock;
  	}
  
  	/* Is update really needed? */
  	if (opp->supplies->u_volt == u_volt)
  		goto adjust_unlock;
  
  	opp->supplies->u_volt = u_volt;
  	opp->supplies->u_volt_min = u_volt_min;
  	opp->supplies->u_volt_max = u_volt_max;
  
  	dev_pm_opp_get(opp);
  	mutex_unlock(&opp_table->lock);
  
  	/* Notify the voltage change of the OPP */
  	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE,
  				     opp);
  
  	dev_pm_opp_put(opp);
  	goto adjust_put_table;
  
  adjust_unlock:
  	mutex_unlock(&opp_table->lock);
  adjust_put_table:
  	dev_pm_opp_put_opp_table(opp_table);
  	return r;
  }
036491542   Valdis Kletnieks   opp: core: Add mi...
2260
  EXPORT_SYMBOL_GPL(dev_pm_opp_adjust_voltage);
25cb20a21   Stephen Boyd   PM / OPP: Support...
2261
2262
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2263
   * dev_pm_opp_enable() - Enable a specific OPP
e1f60b292   Nishanth Menon   PM: Introduce lib...
2264
2265
2266
2267
2268
   * @dev:	device for which we do this operation
   * @freq:	OPP frequency to enable
   *
   * Enables a provided opp. If the operation is valid, this returns 0, else the
   * corresponding error value. It is meant to be used for users an OPP available
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2269
   * after being temporarily made unavailable with dev_pm_opp_disable.
e1f60b292   Nishanth Menon   PM: Introduce lib...
2270
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
2271
   * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
e1a2d49cd   Stephen Boyd   PM / OPP: Fix typ...
2272
   * copy operation, returns 0 if no modification was done OR modification was
984f16c84   Nishanth Menon   PM / OPP: Update ...
2273
   * successful.
e1f60b292   Nishanth Menon   PM: Introduce lib...
2274
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2275
  int dev_pm_opp_enable(struct device *dev, unsigned long freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
2276
  {
327854c87   Nishanth Menon   PM / OPP: Ensure ...
2277
  	return _opp_set_availability(dev, freq, true);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2278
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2279
  EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2280
2281
  
  /**
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2282
   * dev_pm_opp_disable() - Disable a specific OPP
e1f60b292   Nishanth Menon   PM: Introduce lib...
2283
2284
2285
2286
2287
2288
   * @dev:	device for which we do this operation
   * @freq:	OPP frequency to disable
   *
   * Disables a provided opp. If the operation is valid, this returns
   * 0, else the corresponding error value. It is meant to be a temporary
   * control by users to make this OPP not available until the circumstances are
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2289
   * right to make it available again (with a call to dev_pm_opp_enable).
e1f60b292   Nishanth Menon   PM: Introduce lib...
2290
   *
984f16c84   Nishanth Menon   PM / OPP: Update ...
2291
   * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
e1a2d49cd   Stephen Boyd   PM / OPP: Fix typ...
2292
   * copy operation, returns 0 if no modification was done OR modification was
984f16c84   Nishanth Menon   PM / OPP: Update ...
2293
   * successful.
e1f60b292   Nishanth Menon   PM: Introduce lib...
2294
   */
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2295
  int dev_pm_opp_disable(struct device *dev, unsigned long freq)
e1f60b292   Nishanth Menon   PM: Introduce lib...
2296
  {
327854c87   Nishanth Menon   PM / OPP: Ensure ...
2297
  	return _opp_set_availability(dev, freq, false);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2298
  }
5d4879cda   Nishanth Menon   PM / OPP: rename ...
2299
  EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
e1f60b292   Nishanth Menon   PM: Introduce lib...
2300

03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2301
  /**
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2302
2303
2304
   * dev_pm_opp_register_notifier() - Register OPP notifier for the device
   * @dev:	Device for which notifier needs to be registered
   * @nb:		Notifier block to be registered
984f16c84   Nishanth Menon   PM / OPP: Update ...
2305
   *
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2306
2307
2308
2309
2310
2311
   * Return: 0 on success or a negative error value.
   */
  int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
  {
  	struct opp_table *opp_table;
  	int ret;
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2312
  	opp_table = _find_opp_table(dev);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
2313
2314
  	if (IS_ERR(opp_table))
  		return PTR_ERR(opp_table);
052c6f191   Viresh Kumar   PM / OPP: Move aw...
2315
  	ret = blocking_notifier_chain_register(&opp_table->head, nb);
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2316

5b650b388   Viresh Kumar   PM / OPP: Take kr...
2317
  	dev_pm_opp_put_opp_table(opp_table);
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2318
2319
2320
2321
2322
2323
2324
2325
2326
  
  	return ret;
  }
  EXPORT_SYMBOL(dev_pm_opp_register_notifier);
  
  /**
   * dev_pm_opp_unregister_notifier() - Unregister OPP notifier for the device
   * @dev:	Device for which notifier needs to be unregistered
   * @nb:		Notifier block to be unregistered
984f16c84   Nishanth Menon   PM / OPP: Update ...
2327
   *
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2328
   * Return: 0 on success or a negative error value.
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2329
   */
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2330
2331
  int dev_pm_opp_unregister_notifier(struct device *dev,
  				   struct notifier_block *nb)
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2332
  {
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2333
2334
  	struct opp_table *opp_table;
  	int ret;
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2335

dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2336
  	opp_table = _find_opp_table(dev);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
2337
2338
  	if (IS_ERR(opp_table))
  		return PTR_ERR(opp_table);
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2339

052c6f191   Viresh Kumar   PM / OPP: Move aw...
2340
  	ret = blocking_notifier_chain_unregister(&opp_table->head, nb);
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2341

5b650b388   Viresh Kumar   PM / OPP: Take kr...
2342
  	dev_pm_opp_put_opp_table(opp_table);
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2343
2344
  
  	return ret;
03ca370fb   MyungJoo Ham   PM / OPP: Add OPP...
2345
  }
dc2c9ad52   Viresh Kumar   PM / OPP: Don't e...
2346
  EXPORT_SYMBOL(dev_pm_opp_unregister_notifier);
b496dfbc9   Shawn Guo   PM / OPP: Initial...
2347

8aaf6264f   Viresh Kumar   opp: Remove _dev_...
2348
2349
2350
2351
2352
2353
2354
2355
  /**
   * dev_pm_opp_remove_table() - Free all OPPs associated with the device
   * @dev:	device pointer used to lookup OPP table.
   *
   * Free both OPPs created using static entries present in DT and the
   * dynamically added entries.
   */
  void dev_pm_opp_remove_table(struct device *dev)
9274c8924   Viresh Kumar   PM / OPP: Rename ...
2356
2357
  {
  	struct opp_table *opp_table;
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2358
2359
2360
2361
  	/* Check for existing table for 'dev' */
  	opp_table = _find_opp_table(dev);
  	if (IS_ERR(opp_table)) {
  		int error = PTR_ERR(opp_table);
737002b5d   Viresh Kumar   PM / OPP: Relocat...
2362
2363
  
  		if (error != -ENODEV)
2c2709dc6   Viresh Kumar   PM / OPP: Rename ...
2364
2365
  			WARN(1, "%s: opp_table: %d
  ",
737002b5d   Viresh Kumar   PM / OPP: Relocat...
2366
2367
2368
  			     IS_ERR_OR_NULL(dev) ?
  					"Invalid device" : dev_name(dev),
  			     error);
5b650b388   Viresh Kumar   PM / OPP: Take kr...
2369
  		return;
737002b5d   Viresh Kumar   PM / OPP: Relocat...
2370
  	}
922ff0759   Viresh Kumar   opp: Don't drop r...
2371
2372
2373
2374
2375
2376
  	/*
  	 * Drop the extra reference only if the OPP table was successfully added
  	 * with dev_pm_opp_of_add_table() earlier.
  	 **/
  	if (_opp_remove_all_static(opp_table))
  		dev_pm_opp_put_opp_table(opp_table);
cdd6ed90c   Viresh Kumar   OPP: Use a single...
2377
2378
2379
  
  	/* Drop reference taken by _find_opp_table() */
  	dev_pm_opp_put_opp_table(opp_table);
737002b5d   Viresh Kumar   PM / OPP: Relocat...
2380
  }
411466c50   Sudeep Holla   PM / OPP: add non...
2381
  EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);