diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-01-11 19:11:14 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-01-11 19:11:14 -0500 |
commit | 7f4a3702bda0f9f5d34f0241cc81467a55162d7a (patch) | |
tree | 085b220efc86abd24fb44d345bbad2dc44f0f7af | |
parent | a7da4813429cf36abd042e6da72cc6641767d52f (diff) | |
parent | 5ff24d601092b222340b28466e263b1c4559407e (diff) |
Merge branch 'pm-opp'
* pm-opp:
PM / OPP: Use snprintf() instead of sprintf()
PM / OPP: Set cpu_dev->id in cpumask first
PM / OPP: Fix parsing of opp-microvolt and opp-microamp properties
PM / OPP: Parse 'opp-<prop>-<name>' bindings
PM / OPP: Parse 'opp-supported-hw' binding
PM / OPP: Add missing doc comments
ARM: dts: exynos4412: Rename OPP nodes as opp@<opp-hz>
PM / OPP: Rename OPP nodes as opp@<opp-hz>
PM / OPP: Remove 'operating-points-names' binding
PM / OPP: Add {opp-microvolt|opp-microamp}-<name> binding
PM / OPP: Add "opp-supported-hw" binding
PM / OPP: Add debugfs support
-rw-r--r-- | Documentation/devicetree/bindings/opp/opp.txt | 132 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos4412.dtsi | 28 | ||||
-rw-r--r-- | drivers/base/power/opp/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/power/opp/core.c | 336 | ||||
-rw-r--r-- | drivers/base/power/opp/cpu.c | 3 | ||||
-rw-r--r-- | drivers/base/power/opp/debugfs.c | 219 | ||||
-rw-r--r-- | drivers/base/power/opp/opp.h | 53 | ||||
-rw-r--r-- | include/linux/pm_opp.h | 22 |
8 files changed, 722 insertions, 72 deletions
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 0cb44dc21f97..601256fe8c0d 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt | |||
@@ -45,21 +45,10 @@ Devices supporting OPPs must set their "operating-points-v2" property with | |||
45 | phandle to a OPP table in their DT node. The OPP core will use this phandle to | 45 | phandle to a OPP table in their DT node. The OPP core will use this phandle to |
46 | find the operating points for the device. | 46 | find the operating points for the device. |
47 | 47 | ||
48 | Devices may want to choose OPP tables at runtime and so can provide a list of | ||
49 | phandles here. But only *one* of them should be chosen at runtime. This must be | ||
50 | accompanied by a corresponding "operating-points-names" property, to uniquely | ||
51 | identify the OPP tables. | ||
52 | |||
53 | If required, this can be extended for SoC vendor specfic bindings. Such bindings | 48 | If required, this can be extended for SoC vendor specfic bindings. Such bindings |
54 | should be documented as Documentation/devicetree/bindings/power/<vendor>-opp.txt | 49 | should be documented as Documentation/devicetree/bindings/power/<vendor>-opp.txt |
55 | and should have a compatible description like: "operating-points-v2-<vendor>". | 50 | and should have a compatible description like: "operating-points-v2-<vendor>". |
56 | 51 | ||
57 | Optional properties: | ||
58 | - operating-points-names: Names of OPP tables (required if multiple OPP | ||
59 | tables are present), to uniquely identify them. The same list must be present | ||
60 | for all the CPUs which are sharing clock/voltage rails and hence the OPP | ||
61 | tables. | ||
62 | |||
63 | * OPP Table Node | 52 | * OPP Table Node |
64 | 53 | ||
65 | This describes the OPPs belonging to a device. This node can have following | 54 | This describes the OPPs belonging to a device. This node can have following |
@@ -100,6 +89,14 @@ Optional properties: | |||
100 | Entries for multiple regulators must be present in the same order as | 89 | Entries for multiple regulators must be present in the same order as |
101 | regulators are specified in device's DT node. | 90 | regulators are specified in device's DT node. |
102 | 91 | ||
92 | - opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to | ||
93 | the above opp-microvolt property, but allows multiple voltage ranges to be | ||
94 | provided for the same OPP. At runtime, the platform can pick a <name> and | ||
95 | matching opp-microvolt-<name> property will be enabled for all OPPs. If the | ||
96 | platform doesn't pick a specific <name> or the <name> doesn't match with any | ||
97 | opp-microvolt-<name> properties, then opp-microvolt property shall be used, if | ||
98 | present. | ||
99 | |||
103 | - opp-microamp: The maximum current drawn by the device in microamperes | 100 | - opp-microamp: The maximum current drawn by the device in microamperes |
104 | considering system specific parameters (such as transients, process, aging, | 101 | considering system specific parameters (such as transients, process, aging, |
105 | maximum operating temperature range etc.) as necessary. This may be used to | 102 | maximum operating temperature range etc.) as necessary. This may be used to |
@@ -112,6 +109,9 @@ Optional properties: | |||
112 | for few regulators, then this should be marked as zero for them. If it isn't | 109 | for few regulators, then this should be marked as zero for them. If it isn't |
113 | required for any regulator, then this property need not be present. | 110 | required for any regulator, then this property need not be present. |
114 | 111 | ||
112 | - opp-microamp-<name>: Named opp-microamp property. Similar to | ||
113 | opp-microvolt-<name> property, but for microamp instead. | ||
114 | |||
115 | - clock-latency-ns: Specifies the maximum possible transition latency (in | 115 | - clock-latency-ns: Specifies the maximum possible transition latency (in |
116 | nanoseconds) for switching to this OPP from any other OPP. | 116 | nanoseconds) for switching to this OPP from any other OPP. |
117 | 117 | ||
@@ -123,6 +123,26 @@ Optional properties: | |||
123 | - opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in | 123 | - opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in |
124 | the table should have this. | 124 | the table should have this. |
125 | 125 | ||
126 | - opp-supported-hw: This enables us to select only a subset of OPPs from the | ||
127 | larger OPP table, based on what version of the hardware we are running on. We | ||
128 | still can't have multiple nodes with the same opp-hz value in OPP table. | ||
129 | |||
130 | It's an user defined array containing a hierarchy of hardware version numbers, | ||
131 | supported by the OPP. For example: a platform with hierarchy of three levels | ||
132 | of versions (A, B and C), this field should be like <X Y Z>, where X | ||
133 | corresponds to Version hierarchy A, Y corresponds to version hierarchy B and Z | ||
134 | corresponds to version hierarchy C. | ||
135 | |||
136 | Each level of hierarchy is represented by a 32 bit value, and so there can be | ||
137 | only 32 different supported version per hierarchy. i.e. 1 bit per version. A | ||
138 | value of 0xFFFFFFFF will enable the OPP for all versions for that hierarchy | ||
139 | level. And a value of 0x00000000 will disable the OPP completely, and so we | ||
140 | never want that to happen. | ||
141 | |||
142 | If 32 values aren't sufficient for a version hierarchy, than that version | ||
143 | hierarchy can be contained in multiple 32 bit values. i.e. <X Y Z1 Z2> in the | ||
144 | above example, Z1 & Z2 refer to the version hierarchy Z. | ||
145 | |||
126 | - status: Marks the node enabled/disabled. | 146 | - status: Marks the node enabled/disabled. |
127 | 147 | ||
128 | Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. | 148 | Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. |
@@ -157,20 +177,20 @@ Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. | |||
157 | compatible = "operating-points-v2"; | 177 | compatible = "operating-points-v2"; |
158 | opp-shared; | 178 | opp-shared; |
159 | 179 | ||
160 | opp00 { | 180 | opp@1000000000 { |
161 | opp-hz = /bits/ 64 <1000000000>; | 181 | opp-hz = /bits/ 64 <1000000000>; |
162 | opp-microvolt = <970000 975000 985000>; | 182 | opp-microvolt = <970000 975000 985000>; |
163 | opp-microamp = <70000>; | 183 | opp-microamp = <70000>; |
164 | clock-latency-ns = <300000>; | 184 | clock-latency-ns = <300000>; |
165 | opp-suspend; | 185 | opp-suspend; |
166 | }; | 186 | }; |
167 | opp01 { | 187 | opp@1100000000 { |
168 | opp-hz = /bits/ 64 <1100000000>; | 188 | opp-hz = /bits/ 64 <1100000000>; |
169 | opp-microvolt = <980000 1000000 1010000>; | 189 | opp-microvolt = <980000 1000000 1010000>; |
170 | opp-microamp = <80000>; | 190 | opp-microamp = <80000>; |
171 | clock-latency-ns = <310000>; | 191 | clock-latency-ns = <310000>; |
172 | }; | 192 | }; |
173 | opp02 { | 193 | opp@1200000000 { |
174 | opp-hz = /bits/ 64 <1200000000>; | 194 | opp-hz = /bits/ 64 <1200000000>; |
175 | opp-microvolt = <1025000>; | 195 | opp-microvolt = <1025000>; |
176 | clock-latency-ns = <290000>; | 196 | clock-latency-ns = <290000>; |
@@ -236,20 +256,20 @@ independently. | |||
236 | * independently. | 256 | * independently. |
237 | */ | 257 | */ |
238 | 258 | ||
239 | opp00 { | 259 | opp@1000000000 { |
240 | opp-hz = /bits/ 64 <1000000000>; | 260 | opp-hz = /bits/ 64 <1000000000>; |
241 | opp-microvolt = <970000 975000 985000>; | 261 | opp-microvolt = <970000 975000 985000>; |
242 | opp-microamp = <70000>; | 262 | opp-microamp = <70000>; |
243 | clock-latency-ns = <300000>; | 263 | clock-latency-ns = <300000>; |
244 | opp-suspend; | 264 | opp-suspend; |
245 | }; | 265 | }; |
246 | opp01 { | 266 | opp@1100000000 { |
247 | opp-hz = /bits/ 64 <1100000000>; | 267 | opp-hz = /bits/ 64 <1100000000>; |
248 | opp-microvolt = <980000 1000000 1010000>; | 268 | opp-microvolt = <980000 1000000 1010000>; |
249 | opp-microamp = <80000>; | 269 | opp-microamp = <80000>; |
250 | clock-latency-ns = <310000>; | 270 | clock-latency-ns = <310000>; |
251 | }; | 271 | }; |
252 | opp02 { | 272 | opp@1200000000 { |
253 | opp-hz = /bits/ 64 <1200000000>; | 273 | opp-hz = /bits/ 64 <1200000000>; |
254 | opp-microvolt = <1025000>; | 274 | opp-microvolt = <1025000>; |
255 | opp-microamp = <90000; | 275 | opp-microamp = <90000; |
@@ -312,20 +332,20 @@ DVFS state together. | |||
312 | compatible = "operating-points-v2"; | 332 | compatible = "operating-points-v2"; |
313 | opp-shared; | 333 | opp-shared; |
314 | 334 | ||
315 | opp00 { | 335 | opp@1000000000 { |
316 | opp-hz = /bits/ 64 <1000000000>; | 336 | opp-hz = /bits/ 64 <1000000000>; |
317 | opp-microvolt = <970000 975000 985000>; | 337 | opp-microvolt = <970000 975000 985000>; |
318 | opp-microamp = <70000>; | 338 | opp-microamp = <70000>; |
319 | clock-latency-ns = <300000>; | 339 | clock-latency-ns = <300000>; |
320 | opp-suspend; | 340 | opp-suspend; |
321 | }; | 341 | }; |
322 | opp01 { | 342 | opp@1100000000 { |
323 | opp-hz = /bits/ 64 <1100000000>; | 343 | opp-hz = /bits/ 64 <1100000000>; |
324 | opp-microvolt = <980000 1000000 1010000>; | 344 | opp-microvolt = <980000 1000000 1010000>; |
325 | opp-microamp = <80000>; | 345 | opp-microamp = <80000>; |
326 | clock-latency-ns = <310000>; | 346 | clock-latency-ns = <310000>; |
327 | }; | 347 | }; |
328 | opp02 { | 348 | opp@1200000000 { |
329 | opp-hz = /bits/ 64 <1200000000>; | 349 | opp-hz = /bits/ 64 <1200000000>; |
330 | opp-microvolt = <1025000>; | 350 | opp-microvolt = <1025000>; |
331 | opp-microamp = <90000>; | 351 | opp-microamp = <90000>; |
@@ -338,20 +358,20 @@ DVFS state together. | |||
338 | compatible = "operating-points-v2"; | 358 | compatible = "operating-points-v2"; |
339 | opp-shared; | 359 | opp-shared; |
340 | 360 | ||
341 | opp10 { | 361 | opp@1300000000 { |
342 | opp-hz = /bits/ 64 <1300000000>; | 362 | opp-hz = /bits/ 64 <1300000000>; |
343 | opp-microvolt = <1045000 1050000 1055000>; | 363 | opp-microvolt = <1045000 1050000 1055000>; |
344 | opp-microamp = <95000>; | 364 | opp-microamp = <95000>; |
345 | clock-latency-ns = <400000>; | 365 | clock-latency-ns = <400000>; |
346 | opp-suspend; | 366 | opp-suspend; |
347 | }; | 367 | }; |
348 | opp11 { | 368 | opp@1400000000 { |
349 | opp-hz = /bits/ 64 <1400000000>; | 369 | opp-hz = /bits/ 64 <1400000000>; |
350 | opp-microvolt = <1075000>; | 370 | opp-microvolt = <1075000>; |
351 | opp-microamp = <100000>; | 371 | opp-microamp = <100000>; |
352 | clock-latency-ns = <400000>; | 372 | clock-latency-ns = <400000>; |
353 | }; | 373 | }; |
354 | opp12 { | 374 | opp@1500000000 { |
355 | opp-hz = /bits/ 64 <1500000000>; | 375 | opp-hz = /bits/ 64 <1500000000>; |
356 | opp-microvolt = <1010000 1100000 1110000>; | 376 | opp-microvolt = <1010000 1100000 1110000>; |
357 | opp-microamp = <95000>; | 377 | opp-microamp = <95000>; |
@@ -378,7 +398,7 @@ Example 4: Handling multiple regulators | |||
378 | compatible = "operating-points-v2"; | 398 | compatible = "operating-points-v2"; |
379 | opp-shared; | 399 | opp-shared; |
380 | 400 | ||
381 | opp00 { | 401 | opp@1000000000 { |
382 | opp-hz = /bits/ 64 <1000000000>; | 402 | opp-hz = /bits/ 64 <1000000000>; |
383 | opp-microvolt = <970000>, /* Supply 0 */ | 403 | opp-microvolt = <970000>, /* Supply 0 */ |
384 | <960000>, /* Supply 1 */ | 404 | <960000>, /* Supply 1 */ |
@@ -391,7 +411,7 @@ Example 4: Handling multiple regulators | |||
391 | 411 | ||
392 | /* OR */ | 412 | /* OR */ |
393 | 413 | ||
394 | opp00 { | 414 | opp@1000000000 { |
395 | opp-hz = /bits/ 64 <1000000000>; | 415 | opp-hz = /bits/ 64 <1000000000>; |
396 | opp-microvolt = <970000 975000 985000>, /* Supply 0 */ | 416 | opp-microvolt = <970000 975000 985000>, /* Supply 0 */ |
397 | <960000 965000 975000>, /* Supply 1 */ | 417 | <960000 965000 975000>, /* Supply 1 */ |
@@ -404,7 +424,7 @@ Example 4: Handling multiple regulators | |||
404 | 424 | ||
405 | /* OR */ | 425 | /* OR */ |
406 | 426 | ||
407 | opp00 { | 427 | opp@1000000000 { |
408 | opp-hz = /bits/ 64 <1000000000>; | 428 | opp-hz = /bits/ 64 <1000000000>; |
409 | opp-microvolt = <970000 975000 985000>, /* Supply 0 */ | 429 | opp-microvolt = <970000 975000 985000>, /* Supply 0 */ |
410 | <960000 965000 975000>, /* Supply 1 */ | 430 | <960000 965000 975000>, /* Supply 1 */ |
@@ -417,7 +437,8 @@ Example 4: Handling multiple regulators | |||
417 | }; | 437 | }; |
418 | }; | 438 | }; |
419 | 439 | ||
420 | Example 5: Multiple OPP tables | 440 | Example 5: opp-supported-hw |
441 | (example: three level hierarchy of versions: cuts, substrate and process) | ||
421 | 442 | ||
422 | / { | 443 | / { |
423 | cpus { | 444 | cpus { |
@@ -426,40 +447,73 @@ Example 5: Multiple OPP tables | |||
426 | ... | 447 | ... |
427 | 448 | ||
428 | cpu-supply = <&cpu_supply> | 449 | cpu-supply = <&cpu_supply> |
429 | operating-points-v2 = <&cpu0_opp_table_slow>, <&cpu0_opp_table_fast>; | 450 | operating-points-v2 = <&cpu0_opp_table_slow>; |
430 | operating-points-names = "slow", "fast"; | ||
431 | }; | 451 | }; |
432 | }; | 452 | }; |
433 | 453 | ||
434 | cpu0_opp_table_slow: opp_table_slow { | 454 | opp_table { |
435 | compatible = "operating-points-v2"; | 455 | compatible = "operating-points-v2"; |
436 | status = "okay"; | 456 | status = "okay"; |
437 | opp-shared; | 457 | opp-shared; |
438 | 458 | ||
439 | opp00 { | 459 | opp@600000000 { |
460 | /* | ||
461 | * Supports all substrate and process versions for 0xF | ||
462 | * cuts, i.e. only first four cuts. | ||
463 | */ | ||
464 | opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF> | ||
440 | opp-hz = /bits/ 64 <600000000>; | 465 | opp-hz = /bits/ 64 <600000000>; |
466 | opp-microvolt = <900000 915000 925000>; | ||
441 | ... | 467 | ... |
442 | }; | 468 | }; |
443 | 469 | ||
444 | opp01 { | 470 | opp@800000000 { |
471 | /* | ||
472 | * Supports: | ||
473 | * - cuts: only one, 6th cut (represented by 6th bit). | ||
474 | * - substrate: supports 16 different substrate versions | ||
475 | * - process: supports 9 different process versions | ||
476 | */ | ||
477 | opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0> | ||
445 | opp-hz = /bits/ 64 <800000000>; | 478 | opp-hz = /bits/ 64 <800000000>; |
479 | opp-microvolt = <900000 915000 925000>; | ||
446 | ... | 480 | ... |
447 | }; | 481 | }; |
448 | }; | 482 | }; |
483 | }; | ||
484 | |||
485 | Example 6: opp-microvolt-<name>, opp-microamp-<name>: | ||
486 | (example: device with two possible microvolt ranges: slow and fast) | ||
449 | 487 | ||
450 | cpu0_opp_table_fast: opp_table_fast { | 488 | / { |
489 | cpus { | ||
490 | cpu@0 { | ||
491 | compatible = "arm,cortex-a7"; | ||
492 | ... | ||
493 | |||
494 | operating-points-v2 = <&cpu0_opp_table>; | ||
495 | }; | ||
496 | }; | ||
497 | |||
498 | cpu0_opp_table: opp_table0 { | ||
451 | compatible = "operating-points-v2"; | 499 | compatible = "operating-points-v2"; |
452 | status = "okay"; | ||
453 | opp-shared; | 500 | opp-shared; |
454 | 501 | ||
455 | opp10 { | 502 | opp@1000000000 { |
456 | opp-hz = /bits/ 64 <1000000000>; | 503 | opp-hz = /bits/ 64 <1000000000>; |
457 | ... | 504 | opp-microvolt-slow = <900000 915000 925000>; |
505 | opp-microvolt-fast = <970000 975000 985000>; | ||
506 | opp-microamp-slow = <70000>; | ||
507 | opp-microamp-fast = <71000>; | ||
458 | }; | 508 | }; |
459 | 509 | ||
460 | opp11 { | 510 | opp@1200000000 { |
461 | opp-hz = /bits/ 64 <1100000000>; | 511 | opp-hz = /bits/ 64 <1200000000>; |
462 | ... | 512 | opp-microvolt-slow = <900000 915000 925000>, /* Supply vcc0 */ |
513 | <910000 925000 935000>; /* Supply vcc1 */ | ||
514 | opp-microvolt-fast = <970000 975000 985000>, /* Supply vcc0 */ | ||
515 | <960000 965000 975000>; /* Supply vcc1 */ | ||
516 | opp-microamp = <70000>; /* Will be used for both slow/fast */ | ||
463 | }; | 517 | }; |
464 | }; | 518 | }; |
465 | }; | 519 | }; |
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index 294cfe40388d..40beede46e55 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi | |||
@@ -64,73 +64,73 @@ | |||
64 | compatible = "operating-points-v2"; | 64 | compatible = "operating-points-v2"; |
65 | opp-shared; | 65 | opp-shared; |
66 | 66 | ||
67 | opp00 { | 67 | opp@200000000 { |
68 | opp-hz = /bits/ 64 <200000000>; | 68 | opp-hz = /bits/ 64 <200000000>; |
69 | opp-microvolt = <900000>; | 69 | opp-microvolt = <900000>; |
70 | clock-latency-ns = <200000>; | 70 | clock-latency-ns = <200000>; |
71 | }; | 71 | }; |
72 | opp01 { | 72 | opp@300000000 { |
73 | opp-hz = /bits/ 64 <300000000>; | 73 | opp-hz = /bits/ 64 <300000000>; |
74 | opp-microvolt = <900000>; | 74 | opp-microvolt = <900000>; |
75 | clock-latency-ns = <200000>; | 75 | clock-latency-ns = <200000>; |
76 | }; | 76 | }; |
77 | opp02 { | 77 | opp@400000000 { |
78 | opp-hz = /bits/ 64 <400000000>; | 78 | opp-hz = /bits/ 64 <400000000>; |
79 | opp-microvolt = <925000>; | 79 | opp-microvolt = <925000>; |
80 | clock-latency-ns = <200000>; | 80 | clock-latency-ns = <200000>; |
81 | }; | 81 | }; |
82 | opp03 { | 82 | opp@500000000 { |
83 | opp-hz = /bits/ 64 <500000000>; | 83 | opp-hz = /bits/ 64 <500000000>; |
84 | opp-microvolt = <950000>; | 84 | opp-microvolt = <950000>; |
85 | clock-latency-ns = <200000>; | 85 | clock-latency-ns = <200000>; |
86 | }; | 86 | }; |
87 | opp04 { | 87 | opp@600000000 { |
88 | opp-hz = /bits/ 64 <600000000>; | 88 | opp-hz = /bits/ 64 <600000000>; |
89 | opp-microvolt = <975000>; | 89 | opp-microvolt = <975000>; |
90 | clock-latency-ns = <200000>; | 90 | clock-latency-ns = <200000>; |
91 | }; | 91 | }; |
92 | opp05 { | 92 | opp@700000000 { |
93 | opp-hz = /bits/ 64 <700000000>; | 93 | opp-hz = /bits/ 64 <700000000>; |
94 | opp-microvolt = <987500>; | 94 | opp-microvolt = <987500>; |
95 | clock-latency-ns = <200000>; | 95 | clock-latency-ns = <200000>; |
96 | }; | 96 | }; |
97 | opp06 { | 97 | opp@800000000 { |
98 | opp-hz = /bits/ 64 <800000000>; | 98 | opp-hz = /bits/ 64 <800000000>; |
99 | opp-microvolt = <1000000>; | 99 | opp-microvolt = <1000000>; |
100 | clock-latency-ns = <200000>; | 100 | clock-latency-ns = <200000>; |
101 | opp-suspend; | 101 | opp-suspend; |
102 | }; | 102 | }; |
103 | opp07 { | 103 | opp@900000000 { |
104 | opp-hz = /bits/ 64 <900000000>; | 104 | opp-hz = /bits/ 64 <900000000>; |
105 | opp-microvolt = <1037500>; | 105 | opp-microvolt = <1037500>; |
106 | clock-latency-ns = <200000>; | 106 | clock-latency-ns = <200000>; |
107 | }; | 107 | }; |
108 | opp08 { | 108 | opp@1000000000 { |
109 | opp-hz = /bits/ 64 <1000000000>; | 109 | opp-hz = /bits/ 64 <1000000000>; |
110 | opp-microvolt = <1087500>; | 110 | opp-microvolt = <1087500>; |
111 | clock-latency-ns = <200000>; | 111 | clock-latency-ns = <200000>; |
112 | }; | 112 | }; |
113 | opp09 { | 113 | opp@1100000000 { |
114 | opp-hz = /bits/ 64 <1100000000>; | 114 | opp-hz = /bits/ 64 <1100000000>; |
115 | opp-microvolt = <1137500>; | 115 | opp-microvolt = <1137500>; |
116 | clock-latency-ns = <200000>; | 116 | clock-latency-ns = <200000>; |
117 | }; | 117 | }; |
118 | opp10 { | 118 | opp@1200000000 { |
119 | opp-hz = /bits/ 64 <1200000000>; | 119 | opp-hz = /bits/ 64 <1200000000>; |
120 | opp-microvolt = <1187500>; | 120 | opp-microvolt = <1187500>; |
121 | clock-latency-ns = <200000>; | 121 | clock-latency-ns = <200000>; |
122 | }; | 122 | }; |
123 | opp11 { | 123 | opp@1300000000 { |
124 | opp-hz = /bits/ 64 <1300000000>; | 124 | opp-hz = /bits/ 64 <1300000000>; |
125 | opp-microvolt = <1250000>; | 125 | opp-microvolt = <1250000>; |
126 | clock-latency-ns = <200000>; | 126 | clock-latency-ns = <200000>; |
127 | }; | 127 | }; |
128 | opp12 { | 128 | opp@1400000000 { |
129 | opp-hz = /bits/ 64 <1400000000>; | 129 | opp-hz = /bits/ 64 <1400000000>; |
130 | opp-microvolt = <1287500>; | 130 | opp-microvolt = <1287500>; |
131 | clock-latency-ns = <200000>; | 131 | clock-latency-ns = <200000>; |
132 | }; | 132 | }; |
133 | opp13 { | 133 | opp@1500000000 { |
134 | opp-hz = /bits/ 64 <1500000000>; | 134 | opp-hz = /bits/ 64 <1500000000>; |
135 | opp-microvolt = <1350000>; | 135 | opp-microvolt = <1350000>; |
136 | clock-latency-ns = <200000>; | 136 | clock-latency-ns = <200000>; |
diff --git a/drivers/base/power/opp/Makefile b/drivers/base/power/opp/Makefile index 33c1e18c41a4..19837ef04d8e 100644 --- a/drivers/base/power/opp/Makefile +++ b/drivers/base/power/opp/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | 1 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG |
2 | obj-y += core.o cpu.o | 2 | obj-y += core.o cpu.o |
3 | obj-$(CONFIG_DEBUG_FS) += debugfs.o | ||
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index b8e76f75073b..cf351d3dab1c 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c | |||
@@ -463,6 +463,7 @@ static void _kfree_list_dev_rcu(struct rcu_head *head) | |||
463 | static void _remove_list_dev(struct device_list_opp *list_dev, | 463 | static void _remove_list_dev(struct device_list_opp *list_dev, |
464 | struct device_opp *dev_opp) | 464 | struct device_opp *dev_opp) |
465 | { | 465 | { |
466 | opp_debug_unregister(list_dev, dev_opp); | ||
466 | list_del(&list_dev->node); | 467 | list_del(&list_dev->node); |
467 | call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head, | 468 | call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head, |
468 | _kfree_list_dev_rcu); | 469 | _kfree_list_dev_rcu); |
@@ -472,6 +473,7 @@ struct device_list_opp *_add_list_dev(const struct device *dev, | |||
472 | struct device_opp *dev_opp) | 473 | struct device_opp *dev_opp) |
473 | { | 474 | { |
474 | struct device_list_opp *list_dev; | 475 | struct device_list_opp *list_dev; |
476 | int ret; | ||
475 | 477 | ||
476 | list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL); | 478 | list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL); |
477 | if (!list_dev) | 479 | if (!list_dev) |
@@ -481,6 +483,12 @@ struct device_list_opp *_add_list_dev(const struct device *dev, | |||
481 | list_dev->dev = dev; | 483 | list_dev->dev = dev; |
482 | list_add_rcu(&list_dev->node, &dev_opp->dev_list); | 484 | list_add_rcu(&list_dev->node, &dev_opp->dev_list); |
483 | 485 | ||
486 | /* Create debugfs entries for the dev_opp */ | ||
487 | ret = opp_debug_register(list_dev, dev_opp); | ||
488 | if (ret) | ||
489 | dev_err(dev, "%s: Failed to register opp debugfs (%d)\n", | ||
490 | __func__, ret); | ||
491 | |||
484 | return list_dev; | 492 | return list_dev; |
485 | } | 493 | } |
486 | 494 | ||
@@ -551,6 +559,12 @@ static void _remove_device_opp(struct device_opp *dev_opp) | |||
551 | if (!list_empty(&dev_opp->opp_list)) | 559 | if (!list_empty(&dev_opp->opp_list)) |
552 | return; | 560 | return; |
553 | 561 | ||
562 | if (dev_opp->supported_hw) | ||
563 | return; | ||
564 | |||
565 | if (dev_opp->prop_name) | ||
566 | return; | ||
567 | |||
554 | list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, | 568 | list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, |
555 | node); | 569 | node); |
556 | 570 | ||
@@ -596,6 +610,7 @@ static void _opp_remove(struct device_opp *dev_opp, | |||
596 | */ | 610 | */ |
597 | if (notify) | 611 | if (notify) |
598 | srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); | 612 | srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); |
613 | opp_debug_remove_one(opp); | ||
599 | list_del_rcu(&opp->node); | 614 | list_del_rcu(&opp->node); |
600 | call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); | 615 | call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); |
601 | 616 | ||
@@ -673,6 +688,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
673 | { | 688 | { |
674 | struct dev_pm_opp *opp; | 689 | struct dev_pm_opp *opp; |
675 | struct list_head *head = &dev_opp->opp_list; | 690 | struct list_head *head = &dev_opp->opp_list; |
691 | int ret; | ||
676 | 692 | ||
677 | /* | 693 | /* |
678 | * Insert new OPP in order of increasing frequency and discard if | 694 | * Insert new OPP in order of increasing frequency and discard if |
@@ -703,6 +719,11 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
703 | new_opp->dev_opp = dev_opp; | 719 | new_opp->dev_opp = dev_opp; |
704 | list_add_rcu(&new_opp->node, head); | 720 | list_add_rcu(&new_opp->node, head); |
705 | 721 | ||
722 | ret = opp_debug_create_one(new_opp, dev_opp); | ||
723 | if (ret) | ||
724 | dev_err(dev, "%s: Failed to register opp to debugfs (%d)\n", | ||
725 | __func__, ret); | ||
726 | |||
706 | return 0; | 727 | return 0; |
707 | } | 728 | } |
708 | 729 | ||
@@ -776,35 +797,49 @@ unlock: | |||
776 | } | 797 | } |
777 | 798 | ||
778 | /* TODO: Support multiple regulators */ | 799 | /* TODO: Support multiple regulators */ |
779 | static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) | 800 | static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, |
801 | struct device_opp *dev_opp) | ||
780 | { | 802 | { |
781 | u32 microvolt[3] = {0}; | 803 | u32 microvolt[3] = {0}; |
782 | u32 val; | 804 | u32 val; |
783 | int count, ret; | 805 | int count, ret; |
806 | struct property *prop = NULL; | ||
807 | char name[NAME_MAX]; | ||
808 | |||
809 | /* Search for "opp-microvolt-<name>" */ | ||
810 | if (dev_opp->prop_name) { | ||
811 | snprintf(name, sizeof(name), "opp-microvolt-%s", | ||
812 | dev_opp->prop_name); | ||
813 | prop = of_find_property(opp->np, name, NULL); | ||
814 | } | ||
784 | 815 | ||
785 | /* Missing property isn't a problem, but an invalid entry is */ | 816 | if (!prop) { |
786 | if (!of_find_property(opp->np, "opp-microvolt", NULL)) | 817 | /* Search for "opp-microvolt" */ |
787 | return 0; | 818 | sprintf(name, "opp-microvolt"); |
819 | prop = of_find_property(opp->np, name, NULL); | ||
788 | 820 | ||
789 | count = of_property_count_u32_elems(opp->np, "opp-microvolt"); | 821 | /* Missing property isn't a problem, but an invalid entry is */ |
822 | if (!prop) | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | count = of_property_count_u32_elems(opp->np, name); | ||
790 | if (count < 0) { | 827 | if (count < 0) { |
791 | dev_err(dev, "%s: Invalid opp-microvolt property (%d)\n", | 828 | dev_err(dev, "%s: Invalid %s property (%d)\n", |
792 | __func__, count); | 829 | __func__, name, count); |
793 | return count; | 830 | return count; |
794 | } | 831 | } |
795 | 832 | ||
796 | /* There can be one or three elements here */ | 833 | /* There can be one or three elements here */ |
797 | if (count != 1 && count != 3) { | 834 | if (count != 1 && count != 3) { |
798 | dev_err(dev, "%s: Invalid number of elements in opp-microvolt property (%d)\n", | 835 | dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n", |
799 | __func__, count); | 836 | __func__, name, count); |
800 | return -EINVAL; | 837 | return -EINVAL; |
801 | } | 838 | } |
802 | 839 | ||
803 | ret = of_property_read_u32_array(opp->np, "opp-microvolt", microvolt, | 840 | ret = of_property_read_u32_array(opp->np, name, microvolt, count); |
804 | count); | ||
805 | if (ret) { | 841 | if (ret) { |
806 | dev_err(dev, "%s: error parsing opp-microvolt: %d\n", __func__, | 842 | dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret); |
807 | ret); | ||
808 | return -EINVAL; | 843 | return -EINVAL; |
809 | } | 844 | } |
810 | 845 | ||
@@ -812,13 +847,272 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev) | |||
812 | opp->u_volt_min = microvolt[1]; | 847 | opp->u_volt_min = microvolt[1]; |
813 | opp->u_volt_max = microvolt[2]; | 848 | opp->u_volt_max = microvolt[2]; |
814 | 849 | ||
815 | if (!of_property_read_u32(opp->np, "opp-microamp", &val)) | 850 | /* Search for "opp-microamp-<name>" */ |
851 | prop = NULL; | ||
852 | if (dev_opp->prop_name) { | ||
853 | snprintf(name, sizeof(name), "opp-microamp-%s", | ||
854 | dev_opp->prop_name); | ||
855 | prop = of_find_property(opp->np, name, NULL); | ||
856 | } | ||
857 | |||
858 | if (!prop) { | ||
859 | /* Search for "opp-microamp" */ | ||
860 | sprintf(name, "opp-microamp"); | ||
861 | prop = of_find_property(opp->np, name, NULL); | ||
862 | } | ||
863 | |||
864 | if (prop && !of_property_read_u32(opp->np, name, &val)) | ||
816 | opp->u_amp = val; | 865 | opp->u_amp = val; |
817 | 866 | ||
818 | return 0; | 867 | return 0; |
819 | } | 868 | } |
820 | 869 | ||
821 | /** | 870 | /** |
871 | * dev_pm_opp_set_supported_hw() - Set supported platforms | ||
872 | * @dev: Device for which supported-hw has to be set. | ||
873 | * @versions: Array of hierarchy of versions to match. | ||
874 | * @count: Number of elements in the array. | ||
875 | * | ||
876 | * This is required only for the V2 bindings, and it enables a platform to | ||
877 | * specify the hierarchy of versions it supports. OPP layer will then enable | ||
878 | * OPPs, which are available for those versions, based on its 'opp-supported-hw' | ||
879 | * property. | ||
880 | * | ||
881 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
882 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
883 | * to keep the integrity of the internal data structures. Callers should ensure | ||
884 | * that this function is *NOT* called under RCU protection or in contexts where | ||
885 | * mutex cannot be locked. | ||
886 | */ | ||
887 | int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, | ||
888 | unsigned int count) | ||
889 | { | ||
890 | struct device_opp *dev_opp; | ||
891 | int ret = 0; | ||
892 | |||
893 | /* Hold our list modification lock here */ | ||
894 | mutex_lock(&dev_opp_list_lock); | ||
895 | |||
896 | dev_opp = _add_device_opp(dev); | ||
897 | if (!dev_opp) { | ||
898 | ret = -ENOMEM; | ||
899 | goto unlock; | ||
900 | } | ||
901 | |||
902 | /* Make sure there are no concurrent readers while updating dev_opp */ | ||
903 | WARN_ON(!list_empty(&dev_opp->opp_list)); | ||
904 | |||
905 | /* Do we already have a version hierarchy associated with dev_opp? */ | ||
906 | if (dev_opp->supported_hw) { | ||
907 | dev_err(dev, "%s: Already have supported hardware list\n", | ||
908 | __func__); | ||
909 | ret = -EBUSY; | ||
910 | goto err; | ||
911 | } | ||
912 | |||
913 | dev_opp->supported_hw = kmemdup(versions, count * sizeof(*versions), | ||
914 | GFP_KERNEL); | ||
915 | if (!dev_opp->supported_hw) { | ||
916 | ret = -ENOMEM; | ||
917 | goto err; | ||
918 | } | ||
919 | |||
920 | dev_opp->supported_hw_count = count; | ||
921 | mutex_unlock(&dev_opp_list_lock); | ||
922 | return 0; | ||
923 | |||
924 | err: | ||
925 | _remove_device_opp(dev_opp); | ||
926 | unlock: | ||
927 | mutex_unlock(&dev_opp_list_lock); | ||
928 | |||
929 | return ret; | ||
930 | } | ||
931 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); | ||
932 | |||
933 | /** | ||
934 | * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw | ||
935 | * @dev: Device for which supported-hw has to be set. | ||
936 | * | ||
937 | * This is required only for the V2 bindings, and is called for a matching | ||
938 | * dev_pm_opp_set_supported_hw(). Until this is called, the device_opp structure | ||
939 | * will not be freed. | ||
940 | * | ||
941 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
942 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
943 | * to keep the integrity of the internal data structures. Callers should ensure | ||
944 | * that this function is *NOT* called under RCU protection or in contexts where | ||
945 | * mutex cannot be locked. | ||
946 | */ | ||
947 | void dev_pm_opp_put_supported_hw(struct device *dev) | ||
948 | { | ||
949 | struct device_opp *dev_opp; | ||
950 | |||
951 | /* Hold our list modification lock here */ | ||
952 | mutex_lock(&dev_opp_list_lock); | ||
953 | |||
954 | /* Check for existing list for 'dev' first */ | ||
955 | dev_opp = _find_device_opp(dev); | ||
956 | if (IS_ERR(dev_opp)) { | ||
957 | dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp)); | ||
958 | goto unlock; | ||
959 | } | ||
960 | |||
961 | /* Make sure there are no concurrent readers while updating dev_opp */ | ||
962 | WARN_ON(!list_empty(&dev_opp->opp_list)); | ||
963 | |||
964 | if (!dev_opp->supported_hw) { | ||
965 | dev_err(dev, "%s: Doesn't have supported hardware list\n", | ||
966 | __func__); | ||
967 | goto unlock; | ||
968 | } | ||
969 | |||
970 | kfree(dev_opp->supported_hw); | ||
971 | dev_opp->supported_hw = NULL; | ||
972 | dev_opp->supported_hw_count = 0; | ||
973 | |||
974 | /* Try freeing device_opp if this was the last blocking resource */ | ||
975 | _remove_device_opp(dev_opp); | ||
976 | |||
977 | unlock: | ||
978 | mutex_unlock(&dev_opp_list_lock); | ||
979 | } | ||
980 | EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); | ||
981 | |||
982 | /** | ||
983 | * dev_pm_opp_set_prop_name() - Set prop-extn name | ||
984 | * @dev: Device for which the regulator has to be set. | ||
985 | * @name: name to postfix to properties. | ||
986 | * | ||
987 | * This is required only for the V2 bindings, and it enables a platform to | ||
988 | * specify the extn to be used for certain property names. The properties to | ||
989 | * which the extension will apply are opp-microvolt and opp-microamp. OPP core | ||
990 | * should postfix the property name with -<name> while looking for them. | ||
991 | * | ||
992 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
993 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
994 | * to keep the integrity of the internal data structures. Callers should ensure | ||
995 | * that this function is *NOT* called under RCU protection or in contexts where | ||
996 | * mutex cannot be locked. | ||
997 | */ | ||
998 | int dev_pm_opp_set_prop_name(struct device *dev, const char *name) | ||
999 | { | ||
1000 | struct device_opp *dev_opp; | ||
1001 | int ret = 0; | ||
1002 | |||
1003 | /* Hold our list modification lock here */ | ||
1004 | mutex_lock(&dev_opp_list_lock); | ||
1005 | |||
1006 | dev_opp = _add_device_opp(dev); | ||
1007 | if (!dev_opp) { | ||
1008 | ret = -ENOMEM; | ||
1009 | goto unlock; | ||
1010 | } | ||
1011 | |||
1012 | /* Make sure there are no concurrent readers while updating dev_opp */ | ||
1013 | WARN_ON(!list_empty(&dev_opp->opp_list)); | ||
1014 | |||
1015 | /* Do we already have a prop-name associated with dev_opp? */ | ||
1016 | if (dev_opp->prop_name) { | ||
1017 | dev_err(dev, "%s: Already have prop-name %s\n", __func__, | ||
1018 | dev_opp->prop_name); | ||
1019 | ret = -EBUSY; | ||
1020 | goto err; | ||
1021 | } | ||
1022 | |||
1023 | dev_opp->prop_name = kstrdup(name, GFP_KERNEL); | ||
1024 | if (!dev_opp->prop_name) { | ||
1025 | ret = -ENOMEM; | ||
1026 | goto err; | ||
1027 | } | ||
1028 | |||
1029 | mutex_unlock(&dev_opp_list_lock); | ||
1030 | return 0; | ||
1031 | |||
1032 | err: | ||
1033 | _remove_device_opp(dev_opp); | ||
1034 | unlock: | ||
1035 | mutex_unlock(&dev_opp_list_lock); | ||
1036 | |||
1037 | return ret; | ||
1038 | } | ||
1039 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); | ||
1040 | |||
1041 | /** | ||
1042 | * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name | ||
1043 | * @dev: Device for which the regulator has to be set. | ||
1044 | * | ||
1045 | * This is required only for the V2 bindings, and is called for a matching | ||
1046 | * dev_pm_opp_set_prop_name(). Until this is called, the device_opp structure | ||
1047 | * will not be freed. | ||
1048 | * | ||
1049 | * Locking: The internal device_opp and opp structures are RCU protected. | ||
1050 | * Hence this function internally uses RCU updater strategy with mutex locks | ||
1051 | * to keep the integrity of the internal data structures. Callers should ensure | ||
1052 | * that this function is *NOT* called under RCU protection or in contexts where | ||
1053 | * mutex cannot be locked. | ||
1054 | */ | ||
1055 | void dev_pm_opp_put_prop_name(struct device *dev) | ||
1056 | { | ||
1057 | struct device_opp *dev_opp; | ||
1058 | |||
1059 | /* Hold our list modification lock here */ | ||
1060 | mutex_lock(&dev_opp_list_lock); | ||
1061 | |||
1062 | /* Check for existing list for 'dev' first */ | ||
1063 | dev_opp = _find_device_opp(dev); | ||
1064 | if (IS_ERR(dev_opp)) { | ||
1065 | dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp)); | ||
1066 | goto unlock; | ||
1067 | } | ||
1068 | |||
1069 | /* Make sure there are no concurrent readers while updating dev_opp */ | ||
1070 | WARN_ON(!list_empty(&dev_opp->opp_list)); | ||
1071 | |||
1072 | if (!dev_opp->prop_name) { | ||
1073 | dev_err(dev, "%s: Doesn't have a prop-name\n", __func__); | ||
1074 | goto unlock; | ||
1075 | } | ||
1076 | |||
1077 | kfree(dev_opp->prop_name); | ||
1078 | dev_opp->prop_name = NULL; | ||
1079 | |||
1080 | /* Try freeing device_opp if this was the last blocking resource */ | ||
1081 | _remove_device_opp(dev_opp); | ||
1082 | |||
1083 | unlock: | ||
1084 | mutex_unlock(&dev_opp_list_lock); | ||
1085 | } | ||
1086 | EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name); | ||
1087 | |||
1088 | static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp, | ||
1089 | struct device_node *np) | ||
1090 | { | ||
1091 | unsigned int count = dev_opp->supported_hw_count; | ||
1092 | u32 version; | ||
1093 | int ret; | ||
1094 | |||
1095 | if (!dev_opp->supported_hw) | ||
1096 | return true; | ||
1097 | |||
1098 | while (count--) { | ||
1099 | ret = of_property_read_u32_index(np, "opp-supported-hw", count, | ||
1100 | &version); | ||
1101 | if (ret) { | ||
1102 | dev_warn(dev, "%s: failed to read opp-supported-hw property at index %d: %d\n", | ||
1103 | __func__, count, ret); | ||
1104 | return false; | ||
1105 | } | ||
1106 | |||
1107 | /* Both of these are bitwise masks of the versions */ | ||
1108 | if (!(version & dev_opp->supported_hw[count])) | ||
1109 | return false; | ||
1110 | } | ||
1111 | |||
1112 | return true; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
822 | * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) | 1116 | * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) |
823 | * @dev: device for which we do this operation | 1117 | * @dev: device for which we do this operation |
824 | * @np: device node | 1118 | * @np: device node |
@@ -864,6 +1158,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) | |||
864 | goto free_opp; | 1158 | goto free_opp; |
865 | } | 1159 | } |
866 | 1160 | ||
1161 | /* Check if the OPP supports hardware's hierarchy of versions or not */ | ||
1162 | if (!_opp_is_supported(dev, dev_opp, np)) { | ||
1163 | dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate); | ||
1164 | goto free_opp; | ||
1165 | } | ||
1166 | |||
867 | /* | 1167 | /* |
868 | * Rate is defined as an unsigned long in clk API, and so casting | 1168 | * Rate is defined as an unsigned long in clk API, and so casting |
869 | * explicitly to its type. Must be fixed once rate is 64 bit | 1169 | * explicitly to its type. Must be fixed once rate is 64 bit |
@@ -879,7 +1179,7 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) | |||
879 | if (!of_property_read_u32(np, "clock-latency-ns", &val)) | 1179 | if (!of_property_read_u32(np, "clock-latency-ns", &val)) |
880 | new_opp->clock_latency_ns = val; | 1180 | new_opp->clock_latency_ns = val; |
881 | 1181 | ||
882 | ret = opp_parse_supplies(new_opp, dev); | 1182 | ret = opp_parse_supplies(new_opp, dev, dev_opp); |
883 | if (ret) | 1183 | if (ret) |
884 | goto free_opp; | 1184 | goto free_opp; |
885 | 1185 | ||
@@ -889,12 +1189,14 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) | |||
889 | 1189 | ||
890 | /* OPP to select on device suspend */ | 1190 | /* OPP to select on device suspend */ |
891 | if (of_property_read_bool(np, "opp-suspend")) { | 1191 | if (of_property_read_bool(np, "opp-suspend")) { |
892 | if (dev_opp->suspend_opp) | 1192 | if (dev_opp->suspend_opp) { |
893 | dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n", | 1193 | dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n", |
894 | __func__, dev_opp->suspend_opp->rate, | 1194 | __func__, dev_opp->suspend_opp->rate, |
895 | new_opp->rate); | 1195 | new_opp->rate); |
896 | else | 1196 | } else { |
1197 | new_opp->suspend = true; | ||
897 | dev_opp->suspend_opp = new_opp; | 1198 | dev_opp->suspend_opp = new_opp; |
1199 | } | ||
898 | } | 1200 | } |
899 | 1201 | ||
900 | if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max) | 1202 | if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max) |
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 7b445e88a0d5..9f0c15570f64 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c | |||
@@ -214,7 +214,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); | |||
214 | /* | 214 | /* |
215 | * Works only for OPP v2 bindings. | 215 | * Works only for OPP v2 bindings. |
216 | * | 216 | * |
217 | * cpumask should be already set to mask of cpu_dev->id. | ||
218 | * Returns -ENOENT if operating-points-v2 bindings aren't supported. | 217 | * Returns -ENOENT if operating-points-v2 bindings aren't supported. |
219 | */ | 218 | */ |
220 | int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) | 219 | int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) |
@@ -230,6 +229,8 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask | |||
230 | return -ENOENT; | 229 | return -ENOENT; |
231 | } | 230 | } |
232 | 231 | ||
232 | cpumask_set_cpu(cpu_dev->id, cpumask); | ||
233 | |||
233 | /* OPPs are shared ? */ | 234 | /* OPPs are shared ? */ |
234 | if (!of_property_read_bool(np, "opp-shared")) | 235 | if (!of_property_read_bool(np, "opp-shared")) |
235 | goto put_cpu_node; | 236 | goto put_cpu_node; |
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c new file mode 100644 index 000000000000..ddfe4773e922 --- /dev/null +++ b/drivers/base/power/opp/debugfs.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * Generic OPP debugfs interface | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
12 | |||
13 | #include <linux/debugfs.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/limits.h> | ||
18 | |||
19 | #include "opp.h" | ||
20 | |||
21 | static struct dentry *rootdir; | ||
22 | |||
23 | static void opp_set_dev_name(const struct device *dev, char *name) | ||
24 | { | ||
25 | if (dev->parent) | ||
26 | snprintf(name, NAME_MAX, "%s-%s", dev_name(dev->parent), | ||
27 | dev_name(dev)); | ||
28 | else | ||
29 | snprintf(name, NAME_MAX, "%s", dev_name(dev)); | ||
30 | } | ||
31 | |||
32 | void opp_debug_remove_one(struct dev_pm_opp *opp) | ||
33 | { | ||
34 | debugfs_remove_recursive(opp->dentry); | ||
35 | } | ||
36 | |||
37 | int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp) | ||
38 | { | ||
39 | struct dentry *pdentry = dev_opp->dentry; | ||
40 | struct dentry *d; | ||
41 | char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ | ||
42 | |||
43 | /* Rate is unique to each OPP, use it to give opp-name */ | ||
44 | snprintf(name, sizeof(name), "opp:%lu", opp->rate); | ||
45 | |||
46 | /* Create per-opp directory */ | ||
47 | d = debugfs_create_dir(name, pdentry); | ||
48 | if (!d) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | if (!debugfs_create_bool("available", S_IRUGO, d, &opp->available)) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | if (!debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic)) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | if (!debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo)) | ||
58 | return -ENOMEM; | ||
59 | |||
60 | if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend)) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) | ||
64 | return -ENOMEM; | ||
65 | |||
66 | if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt)) | ||
67 | return -ENOMEM; | ||
68 | |||
69 | if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min)) | ||
70 | return -ENOMEM; | ||
71 | |||
72 | if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max)) | ||
73 | return -ENOMEM; | ||
74 | |||
75 | if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp)) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, | ||
79 | &opp->clock_latency_ns)) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | opp->dentry = d; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int device_opp_debug_create_dir(struct device_list_opp *list_dev, | ||
87 | struct device_opp *dev_opp) | ||
88 | { | ||
89 | const struct device *dev = list_dev->dev; | ||
90 | struct dentry *d; | ||
91 | |||
92 | opp_set_dev_name(dev, dev_opp->dentry_name); | ||
93 | |||
94 | /* Create device specific directory */ | ||
95 | d = debugfs_create_dir(dev_opp->dentry_name, rootdir); | ||
96 | if (!d) { | ||
97 | dev_err(dev, "%s: Failed to create debugfs dir\n", __func__); | ||
98 | return -ENOMEM; | ||
99 | } | ||
100 | |||
101 | list_dev->dentry = d; | ||
102 | dev_opp->dentry = d; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int device_opp_debug_create_link(struct device_list_opp *list_dev, | ||
108 | struct device_opp *dev_opp) | ||
109 | { | ||
110 | const struct device *dev = list_dev->dev; | ||
111 | char name[NAME_MAX]; | ||
112 | struct dentry *d; | ||
113 | |||
114 | opp_set_dev_name(list_dev->dev, name); | ||
115 | |||
116 | /* Create device specific directory link */ | ||
117 | d = debugfs_create_symlink(name, rootdir, dev_opp->dentry_name); | ||
118 | if (!d) { | ||
119 | dev_err(dev, "%s: Failed to create link\n", __func__); | ||
120 | return -ENOMEM; | ||
121 | } | ||
122 | |||
123 | list_dev->dentry = d; | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * opp_debug_register - add a device opp node to the debugfs 'opp' directory | ||
130 | * @list_dev: list-dev pointer for device | ||
131 | * @dev_opp: the device-opp being added | ||
132 | * | ||
133 | * Dynamically adds device specific directory in debugfs 'opp' directory. If the | ||
134 | * device-opp is shared with other devices, then links will be created for all | ||
135 | * devices except the first. | ||
136 | * | ||
137 | * Return: 0 on success, otherwise negative error. | ||
138 | */ | ||
139 | int opp_debug_register(struct device_list_opp *list_dev, | ||
140 | struct device_opp *dev_opp) | ||
141 | { | ||
142 | if (!rootdir) { | ||
143 | pr_debug("%s: Uninitialized rootdir\n", __func__); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | if (dev_opp->dentry) | ||
148 | return device_opp_debug_create_link(list_dev, dev_opp); | ||
149 | |||
150 | return device_opp_debug_create_dir(list_dev, dev_opp); | ||
151 | } | ||
152 | |||
153 | static void opp_migrate_dentry(struct device_list_opp *list_dev, | ||
154 | struct device_opp *dev_opp) | ||
155 | { | ||
156 | struct device_list_opp *new_dev; | ||
157 | const struct device *dev; | ||
158 | struct dentry *dentry; | ||
159 | |||
160 | /* Look for next list-dev */ | ||
161 | list_for_each_entry(new_dev, &dev_opp->dev_list, node) | ||
162 | if (new_dev != list_dev) | ||
163 | break; | ||
164 | |||
165 | /* new_dev is guaranteed to be valid here */ | ||
166 | dev = new_dev->dev; | ||
167 | debugfs_remove_recursive(new_dev->dentry); | ||
168 | |||
169 | opp_set_dev_name(dev, dev_opp->dentry_name); | ||
170 | |||
171 | dentry = debugfs_rename(rootdir, list_dev->dentry, rootdir, | ||
172 | dev_opp->dentry_name); | ||
173 | if (!dentry) { | ||
174 | dev_err(dev, "%s: Failed to rename link from: %s to %s\n", | ||
175 | __func__, dev_name(list_dev->dev), dev_name(dev)); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | new_dev->dentry = dentry; | ||
180 | dev_opp->dentry = dentry; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * opp_debug_unregister - remove a device opp node from debugfs opp directory | ||
185 | * @list_dev: list-dev pointer for device | ||
186 | * @dev_opp: the device-opp being removed | ||
187 | * | ||
188 | * Dynamically removes device specific directory from debugfs 'opp' directory. | ||
189 | */ | ||
190 | void opp_debug_unregister(struct device_list_opp *list_dev, | ||
191 | struct device_opp *dev_opp) | ||
192 | { | ||
193 | if (list_dev->dentry == dev_opp->dentry) { | ||
194 | /* Move the real dentry object under another device */ | ||
195 | if (!list_is_singular(&dev_opp->dev_list)) { | ||
196 | opp_migrate_dentry(list_dev, dev_opp); | ||
197 | goto out; | ||
198 | } | ||
199 | dev_opp->dentry = NULL; | ||
200 | } | ||
201 | |||
202 | debugfs_remove_recursive(list_dev->dentry); | ||
203 | |||
204 | out: | ||
205 | list_dev->dentry = NULL; | ||
206 | } | ||
207 | |||
208 | static int __init opp_debug_init(void) | ||
209 | { | ||
210 | /* Create /sys/kernel/debug/opp directory */ | ||
211 | rootdir = debugfs_create_dir("opp", NULL); | ||
212 | if (!rootdir) { | ||
213 | pr_err("%s: Failed to create root directory\n", __func__); | ||
214 | return -ENOMEM; | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | core_initcall(opp_debug_init); | ||
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 7366b2aa8997..690638ef36ee 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/limits.h> | ||
20 | #include <linux/pm_opp.h> | 21 | #include <linux/pm_opp.h> |
21 | #include <linux/rculist.h> | 22 | #include <linux/rculist.h> |
22 | #include <linux/rcupdate.h> | 23 | #include <linux/rcupdate.h> |
@@ -50,9 +51,10 @@ extern struct mutex dev_opp_list_lock; | |||
50 | * are protected by the dev_opp_list_lock for integrity. | 51 | * are protected by the dev_opp_list_lock for integrity. |
51 | * IMPORTANT: the opp nodes should be maintained in increasing | 52 | * IMPORTANT: the opp nodes should be maintained in increasing |
52 | * order. | 53 | * order. |
53 | * @dynamic: not-created from static DT entries. | ||
54 | * @available: true/false - marks if this OPP as available or not | 54 | * @available: true/false - marks if this OPP as available or not |
55 | * @dynamic: not-created from static DT entries. | ||
55 | * @turbo: true if turbo (boost) OPP | 56 | * @turbo: true if turbo (boost) OPP |
57 | * @suspend: true if suspend OPP | ||
56 | * @rate: Frequency in hertz | 58 | * @rate: Frequency in hertz |
57 | * @u_volt: Target voltage in microvolts corresponding to this OPP | 59 | * @u_volt: Target voltage in microvolts corresponding to this OPP |
58 | * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP | 60 | * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP |
@@ -63,6 +65,7 @@ extern struct mutex dev_opp_list_lock; | |||
63 | * @dev_opp: points back to the device_opp struct this opp belongs to | 65 | * @dev_opp: points back to the device_opp struct this opp belongs to |
64 | * @rcu_head: RCU callback head used for deferred freeing | 66 | * @rcu_head: RCU callback head used for deferred freeing |
65 | * @np: OPP's device node. | 67 | * @np: OPP's device node. |
68 | * @dentry: debugfs dentry pointer (per opp) | ||
66 | * | 69 | * |
67 | * This structure stores the OPP information for a given device. | 70 | * This structure stores the OPP information for a given device. |
68 | */ | 71 | */ |
@@ -72,6 +75,7 @@ struct dev_pm_opp { | |||
72 | bool available; | 75 | bool available; |
73 | bool dynamic; | 76 | bool dynamic; |
74 | bool turbo; | 77 | bool turbo; |
78 | bool suspend; | ||
75 | unsigned long rate; | 79 | unsigned long rate; |
76 | 80 | ||
77 | unsigned long u_volt; | 81 | unsigned long u_volt; |
@@ -84,6 +88,10 @@ struct dev_pm_opp { | |||
84 | struct rcu_head rcu_head; | 88 | struct rcu_head rcu_head; |
85 | 89 | ||
86 | struct device_node *np; | 90 | struct device_node *np; |
91 | |||
92 | #ifdef CONFIG_DEBUG_FS | ||
93 | struct dentry *dentry; | ||
94 | #endif | ||
87 | }; | 95 | }; |
88 | 96 | ||
89 | /** | 97 | /** |
@@ -91,6 +99,7 @@ struct dev_pm_opp { | |||
91 | * @node: list node | 99 | * @node: list node |
92 | * @dev: device to which the struct object belongs | 100 | * @dev: device to which the struct object belongs |
93 | * @rcu_head: RCU callback head used for deferred freeing | 101 | * @rcu_head: RCU callback head used for deferred freeing |
102 | * @dentry: debugfs dentry pointer (per device) | ||
94 | * | 103 | * |
95 | * This is an internal data structure maintaining the list of devices that are | 104 | * This is an internal data structure maintaining the list of devices that are |
96 | * managed by 'struct device_opp'. | 105 | * managed by 'struct device_opp'. |
@@ -99,6 +108,10 @@ struct device_list_opp { | |||
99 | struct list_head node; | 108 | struct list_head node; |
100 | const struct device *dev; | 109 | const struct device *dev; |
101 | struct rcu_head rcu_head; | 110 | struct rcu_head rcu_head; |
111 | |||
112 | #ifdef CONFIG_DEBUG_FS | ||
113 | struct dentry *dentry; | ||
114 | #endif | ||
102 | }; | 115 | }; |
103 | 116 | ||
104 | /** | 117 | /** |
@@ -113,7 +126,14 @@ struct device_list_opp { | |||
113 | * @dev_list: list of devices that share these OPPs | 126 | * @dev_list: list of devices that share these OPPs |
114 | * @opp_list: list of opps | 127 | * @opp_list: list of opps |
115 | * @np: struct device_node pointer for opp's DT node. | 128 | * @np: struct device_node pointer for opp's DT node. |
129 | * @clock_latency_ns_max: Max clock latency in nanoseconds. | ||
116 | * @shared_opp: OPP is shared between multiple devices. | 130 | * @shared_opp: OPP is shared between multiple devices. |
131 | * @suspend_opp: Pointer to OPP to be used during device suspend. | ||
132 | * @supported_hw: Array of version number to support. | ||
133 | * @supported_hw_count: Number of elements in supported_hw array. | ||
134 | * @prop_name: A name to postfix to many DT properties, while parsing them. | ||
135 | * @dentry: debugfs dentry pointer of the real device directory (not links). | ||
136 | * @dentry_name: Name of the real dentry. | ||
117 | * | 137 | * |
118 | * This is an internal data structure maintaining the link to opps attached to | 138 | * This is an internal data structure maintaining the link to opps attached to |
119 | * a device. This structure is not meant to be shared to users as it is | 139 | * a device. This structure is not meant to be shared to users as it is |
@@ -135,6 +155,15 @@ struct device_opp { | |||
135 | unsigned long clock_latency_ns_max; | 155 | unsigned long clock_latency_ns_max; |
136 | bool shared_opp; | 156 | bool shared_opp; |
137 | struct dev_pm_opp *suspend_opp; | 157 | struct dev_pm_opp *suspend_opp; |
158 | |||
159 | unsigned int *supported_hw; | ||
160 | unsigned int supported_hw_count; | ||
161 | const char *prop_name; | ||
162 | |||
163 | #ifdef CONFIG_DEBUG_FS | ||
164 | struct dentry *dentry; | ||
165 | char dentry_name[NAME_MAX]; | ||
166 | #endif | ||
138 | }; | 167 | }; |
139 | 168 | ||
140 | /* Routines internal to opp core */ | 169 | /* Routines internal to opp core */ |
@@ -143,4 +172,26 @@ struct device_list_opp *_add_list_dev(const struct device *dev, | |||
143 | struct device_opp *dev_opp); | 172 | struct device_opp *dev_opp); |
144 | struct device_node *_of_get_opp_desc_node(struct device *dev); | 173 | struct device_node *_of_get_opp_desc_node(struct device *dev); |
145 | 174 | ||
175 | #ifdef CONFIG_DEBUG_FS | ||
176 | void opp_debug_remove_one(struct dev_pm_opp *opp); | ||
177 | int opp_debug_create_one(struct dev_pm_opp *opp, struct device_opp *dev_opp); | ||
178 | int opp_debug_register(struct device_list_opp *list_dev, | ||
179 | struct device_opp *dev_opp); | ||
180 | void opp_debug_unregister(struct device_list_opp *list_dev, | ||
181 | struct device_opp *dev_opp); | ||
182 | #else | ||
183 | static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {} | ||
184 | |||
185 | static inline int opp_debug_create_one(struct dev_pm_opp *opp, | ||
186 | struct device_opp *dev_opp) | ||
187 | { return 0; } | ||
188 | static inline int opp_debug_register(struct device_list_opp *list_dev, | ||
189 | struct device_opp *dev_opp) | ||
190 | { return 0; } | ||
191 | |||
192 | static inline void opp_debug_unregister(struct device_list_opp *list_dev, | ||
193 | struct device_opp *dev_opp) | ||
194 | { } | ||
195 | #endif /* DEBUG_FS */ | ||
196 | |||
146 | #endif /* __DRIVER_OPP_H__ */ | 197 | #endif /* __DRIVER_OPP_H__ */ |
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 9a2e50337af9..95403d2ccaf5 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h | |||
@@ -55,6 +55,11 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq); | |||
55 | int dev_pm_opp_disable(struct device *dev, unsigned long freq); | 55 | int dev_pm_opp_disable(struct device *dev, unsigned long freq); |
56 | 56 | ||
57 | struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev); | 57 | struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev); |
58 | int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, | ||
59 | unsigned int count); | ||
60 | void dev_pm_opp_put_supported_hw(struct device *dev); | ||
61 | int dev_pm_opp_set_prop_name(struct device *dev, const char *name); | ||
62 | void dev_pm_opp_put_prop_name(struct device *dev); | ||
58 | #else | 63 | #else |
59 | static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) | 64 | static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) |
60 | { | 65 | { |
@@ -129,6 +134,23 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( | |||
129 | { | 134 | { |
130 | return ERR_PTR(-EINVAL); | 135 | return ERR_PTR(-EINVAL); |
131 | } | 136 | } |
137 | |||
138 | static inline int dev_pm_opp_set_supported_hw(struct device *dev, | ||
139 | const u32 *versions, | ||
140 | unsigned int count) | ||
141 | { | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | static inline void dev_pm_opp_put_supported_hw(struct device *dev) {} | ||
146 | |||
147 | static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name) | ||
148 | { | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | static inline void dev_pm_opp_put_prop_name(struct device *dev) {} | ||
153 | |||
132 | #endif /* CONFIG_PM_OPP */ | 154 | #endif /* CONFIG_PM_OPP */ |
133 | 155 | ||
134 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) | 156 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) |