diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/clock_ops.c | 150 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 147 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 11 | ||||
-rw-r--r-- | drivers/base/power/power.h | 56 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 5 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 76 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 19 | ||||
-rw-r--r-- | drivers/base/property.c | 431 |
9 files changed, 616 insertions, 281 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 6922cd6850a2..53c3fe1aeb29 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \ | |||
4 | driver.o class.o platform.o \ | 4 | driver.o class.o platform.o \ |
5 | cpu.o firmware.o init.o map.o devres.o \ | 5 | cpu.o firmware.o init.o map.o devres.o \ |
6 | attribute_container.o transport_class.o \ | 6 | attribute_container.o transport_class.o \ |
7 | topology.o container.o | 7 | topology.o container.o property.o |
8 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o | 8 | obj-$(CONFIG_DEVTMPFS) += devtmpfs.o |
9 | obj-$(CONFIG_DMA_CMA) += dma-contiguous.o | 9 | obj-$(CONFIG_DMA_CMA) += dma-contiguous.o |
10 | obj-y += power/ | 10 | obj-y += power/ |
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 78369305e069..d626576a4f75 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
13 | #include <linux/pm_clock.h> | 13 | #include <linux/pm_clock.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/clkdev.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
17 | 18 | ||
@@ -34,14 +35,20 @@ struct pm_clock_entry { | |||
34 | /** | 35 | /** |
35 | * pm_clk_enable - Enable a clock, reporting any errors | 36 | * pm_clk_enable - Enable a clock, reporting any errors |
36 | * @dev: The device for the given clock | 37 | * @dev: The device for the given clock |
37 | * @clk: The clock being enabled. | 38 | * @ce: PM clock entry corresponding to the clock. |
38 | */ | 39 | */ |
39 | static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | 40 | static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) |
40 | { | 41 | { |
41 | int ret = clk_enable(clk); | 42 | int ret; |
42 | if (ret) | 43 | |
43 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | 44 | if (ce->status < PCE_STATUS_ERROR) { |
44 | __func__, clk, ret); | 45 | ret = clk_enable(ce->clk); |
46 | if (!ret) | ||
47 | ce->status = PCE_STATUS_ENABLED; | ||
48 | else | ||
49 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | ||
50 | __func__, ce->clk, ret); | ||
51 | } | ||
45 | 52 | ||
46 | return ret; | 53 | return ret; |
47 | } | 54 | } |
@@ -53,7 +60,8 @@ static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | |||
53 | */ | 60 | */ |
54 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | 61 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) |
55 | { | 62 | { |
56 | ce->clk = clk_get(dev, ce->con_id); | 63 | if (!ce->clk) |
64 | ce->clk = clk_get(dev, ce->con_id); | ||
57 | if (IS_ERR(ce->clk)) { | 65 | if (IS_ERR(ce->clk)) { |
58 | ce->status = PCE_STATUS_ERROR; | 66 | ce->status = PCE_STATUS_ERROR; |
59 | } else { | 67 | } else { |
@@ -63,15 +71,8 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | |||
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
66 | /** | 74 | static int __pm_clk_add(struct device *dev, const char *con_id, |
67 | * pm_clk_add - Start using a device clock for power management. | 75 | struct clk *clk) |
68 | * @dev: Device whose clock is going to be used for power management. | ||
69 | * @con_id: Connection ID of the clock. | ||
70 | * | ||
71 | * Add the clock represented by @con_id to the list of clocks used for | ||
72 | * the power management of @dev. | ||
73 | */ | ||
74 | int pm_clk_add(struct device *dev, const char *con_id) | ||
75 | { | 76 | { |
76 | struct pm_subsys_data *psd = dev_to_psd(dev); | 77 | struct pm_subsys_data *psd = dev_to_psd(dev); |
77 | struct pm_clock_entry *ce; | 78 | struct pm_clock_entry *ce; |
@@ -93,6 +94,12 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
93 | kfree(ce); | 94 | kfree(ce); |
94 | return -ENOMEM; | 95 | return -ENOMEM; |
95 | } | 96 | } |
97 | } else { | ||
98 | if (IS_ERR(ce->clk) || !__clk_get(clk)) { | ||
99 | kfree(ce); | ||
100 | return -ENOENT; | ||
101 | } | ||
102 | ce->clk = clk; | ||
96 | } | 103 | } |
97 | 104 | ||
98 | pm_clk_acquire(dev, ce); | 105 | pm_clk_acquire(dev, ce); |
@@ -104,6 +111,32 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
104 | } | 111 | } |
105 | 112 | ||
106 | /** | 113 | /** |
114 | * pm_clk_add - Start using a device clock for power management. | ||
115 | * @dev: Device whose clock is going to be used for power management. | ||
116 | * @con_id: Connection ID of the clock. | ||
117 | * | ||
118 | * Add the clock represented by @con_id to the list of clocks used for | ||
119 | * the power management of @dev. | ||
120 | */ | ||
121 | int pm_clk_add(struct device *dev, const char *con_id) | ||
122 | { | ||
123 | return __pm_clk_add(dev, con_id, NULL); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * pm_clk_add_clk - Start using a device clock for power management. | ||
128 | * @dev: Device whose clock is going to be used for power management. | ||
129 | * @clk: Clock pointer | ||
130 | * | ||
131 | * Add the clock to the list of clocks used for the power management of @dev. | ||
132 | * It will increment refcount on clock pointer, use clk_put() on it when done. | ||
133 | */ | ||
134 | int pm_clk_add_clk(struct device *dev, struct clk *clk) | ||
135 | { | ||
136 | return __pm_clk_add(dev, NULL, clk); | ||
137 | } | ||
138 | |||
139 | /** | ||
107 | * __pm_clk_remove - Destroy PM clock entry. | 140 | * __pm_clk_remove - Destroy PM clock entry. |
108 | * @ce: PM clock entry to destroy. | 141 | * @ce: PM clock entry to destroy. |
109 | */ | 142 | */ |
@@ -223,10 +256,6 @@ void pm_clk_destroy(struct device *dev) | |||
223 | } | 256 | } |
224 | } | 257 | } |
225 | 258 | ||
226 | #endif /* CONFIG_PM */ | ||
227 | |||
228 | #ifdef CONFIG_PM_RUNTIME | ||
229 | |||
230 | /** | 259 | /** |
231 | * pm_clk_suspend - Disable clocks in a device's PM clock list. | 260 | * pm_clk_suspend - Disable clocks in a device's PM clock list. |
232 | * @dev: Device to disable the clocks for. | 261 | * @dev: Device to disable the clocks for. |
@@ -266,7 +295,6 @@ int pm_clk_resume(struct device *dev) | |||
266 | struct pm_subsys_data *psd = dev_to_psd(dev); | 295 | struct pm_subsys_data *psd = dev_to_psd(dev); |
267 | struct pm_clock_entry *ce; | 296 | struct pm_clock_entry *ce; |
268 | unsigned long flags; | 297 | unsigned long flags; |
269 | int ret; | ||
270 | 298 | ||
271 | dev_dbg(dev, "%s()\n", __func__); | 299 | dev_dbg(dev, "%s()\n", __func__); |
272 | 300 | ||
@@ -275,13 +303,8 @@ int pm_clk_resume(struct device *dev) | |||
275 | 303 | ||
276 | spin_lock_irqsave(&psd->lock, flags); | 304 | spin_lock_irqsave(&psd->lock, flags); |
277 | 305 | ||
278 | list_for_each_entry(ce, &psd->clock_list, node) { | 306 | list_for_each_entry(ce, &psd->clock_list, node) |
279 | if (ce->status < PCE_STATUS_ERROR) { | 307 | __pm_clk_enable(dev, ce); |
280 | ret = __pm_clk_enable(dev, ce->clk); | ||
281 | if (!ret) | ||
282 | ce->status = PCE_STATUS_ENABLED; | ||
283 | } | ||
284 | } | ||
285 | 308 | ||
286 | spin_unlock_irqrestore(&psd->lock, flags); | 309 | spin_unlock_irqrestore(&psd->lock, flags); |
287 | 310 | ||
@@ -346,74 +369,7 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
346 | return 0; | 369 | return 0; |
347 | } | 370 | } |
348 | 371 | ||
349 | #else /* !CONFIG_PM_RUNTIME */ | 372 | #else /* !CONFIG_PM */ |
350 | |||
351 | #ifdef CONFIG_PM | ||
352 | |||
353 | /** | ||
354 | * pm_clk_suspend - Disable clocks in a device's PM clock list. | ||
355 | * @dev: Device to disable the clocks for. | ||
356 | */ | ||
357 | int pm_clk_suspend(struct device *dev) | ||
358 | { | ||
359 | struct pm_subsys_data *psd = dev_to_psd(dev); | ||
360 | struct pm_clock_entry *ce; | ||
361 | unsigned long flags; | ||
362 | |||
363 | dev_dbg(dev, "%s()\n", __func__); | ||
364 | |||
365 | /* If there is no driver, the clocks are already disabled. */ | ||
366 | if (!psd || !dev->driver) | ||
367 | return 0; | ||
368 | |||
369 | spin_lock_irqsave(&psd->lock, flags); | ||
370 | |||
371 | list_for_each_entry_reverse(ce, &psd->clock_list, node) { | ||
372 | if (ce->status < PCE_STATUS_ERROR) { | ||
373 | if (ce->status == PCE_STATUS_ENABLED) | ||
374 | clk_disable(ce->clk); | ||
375 | ce->status = PCE_STATUS_ACQUIRED; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | spin_unlock_irqrestore(&psd->lock, flags); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * pm_clk_resume - Enable clocks in a device's PM clock list. | ||
386 | * @dev: Device to enable the clocks for. | ||
387 | */ | ||
388 | int pm_clk_resume(struct device *dev) | ||
389 | { | ||
390 | struct pm_subsys_data *psd = dev_to_psd(dev); | ||
391 | struct pm_clock_entry *ce; | ||
392 | unsigned long flags; | ||
393 | int ret; | ||
394 | |||
395 | dev_dbg(dev, "%s()\n", __func__); | ||
396 | |||
397 | /* If there is no driver, the clocks should remain disabled. */ | ||
398 | if (!psd || !dev->driver) | ||
399 | return 0; | ||
400 | |||
401 | spin_lock_irqsave(&psd->lock, flags); | ||
402 | |||
403 | list_for_each_entry(ce, &psd->clock_list, node) { | ||
404 | if (ce->status < PCE_STATUS_ERROR) { | ||
405 | ret = __pm_clk_enable(dev, ce->clk); | ||
406 | if (!ret) | ||
407 | ce->status = PCE_STATUS_ENABLED; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | spin_unlock_irqrestore(&psd->lock, flags); | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | #endif /* CONFIG_PM */ | ||
417 | 373 | ||
418 | /** | 374 | /** |
419 | * enable_clock - Enable a device clock. | 375 | * enable_clock - Enable a device clock. |
@@ -493,7 +449,7 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
493 | return 0; | 449 | return 0; |
494 | } | 450 | } |
495 | 451 | ||
496 | #endif /* !CONFIG_PM_RUNTIME */ | 452 | #endif /* !CONFIG_PM */ |
497 | 453 | ||
498 | /** | 454 | /** |
499 | * pm_clk_add_notifier - Add bus type notifier for power management clocks. | 455 | * pm_clk_add_notifier - Add bus type notifier for power management clocks. |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index fb83d4acd400..6a103a35ea9b 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pm_runtime.h> | 12 | #include <linux/pm_runtime.h> |
13 | #include <linux/pm_domain.h> | 13 | #include <linux/pm_domain.h> |
14 | #include <linux/pm_qos.h> | 14 | #include <linux/pm_qos.h> |
15 | #include <linux/pm_clock.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
17 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
@@ -151,6 +152,59 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd) | |||
151 | genpd->cpuidle_data->idle_state->exit_latency = usecs64; | 152 | genpd->cpuidle_data->idle_state->exit_latency = usecs64; |
152 | } | 153 | } |
153 | 154 | ||
155 | static int genpd_power_on(struct generic_pm_domain *genpd) | ||
156 | { | ||
157 | ktime_t time_start; | ||
158 | s64 elapsed_ns; | ||
159 | int ret; | ||
160 | |||
161 | if (!genpd->power_on) | ||
162 | return 0; | ||
163 | |||
164 | time_start = ktime_get(); | ||
165 | ret = genpd->power_on(genpd); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
170 | if (elapsed_ns <= genpd->power_on_latency_ns) | ||
171 | return ret; | ||
172 | |||
173 | genpd->power_on_latency_ns = elapsed_ns; | ||
174 | genpd->max_off_time_changed = true; | ||
175 | genpd_recalc_cpu_exit_latency(genpd); | ||
176 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | ||
177 | genpd->name, "on", elapsed_ns); | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static int genpd_power_off(struct generic_pm_domain *genpd) | ||
183 | { | ||
184 | ktime_t time_start; | ||
185 | s64 elapsed_ns; | ||
186 | int ret; | ||
187 | |||
188 | if (!genpd->power_off) | ||
189 | return 0; | ||
190 | |||
191 | time_start = ktime_get(); | ||
192 | ret = genpd->power_off(genpd); | ||
193 | if (ret == -EBUSY) | ||
194 | return ret; | ||
195 | |||
196 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
197 | if (elapsed_ns <= genpd->power_off_latency_ns) | ||
198 | return ret; | ||
199 | |||
200 | genpd->power_off_latency_ns = elapsed_ns; | ||
201 | genpd->max_off_time_changed = true; | ||
202 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | ||
203 | genpd->name, "off", elapsed_ns); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
154 | /** | 208 | /** |
155 | * __pm_genpd_poweron - Restore power to a given PM domain and its masters. | 209 | * __pm_genpd_poweron - Restore power to a given PM domain and its masters. |
156 | * @genpd: PM domain to power up. | 210 | * @genpd: PM domain to power up. |
@@ -222,25 +276,9 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) | |||
222 | } | 276 | } |
223 | } | 277 | } |
224 | 278 | ||
225 | if (genpd->power_on) { | 279 | ret = genpd_power_on(genpd); |
226 | ktime_t time_start = ktime_get(); | 280 | if (ret) |
227 | s64 elapsed_ns; | 281 | goto err; |
228 | |||
229 | ret = genpd->power_on(genpd); | ||
230 | if (ret) | ||
231 | goto err; | ||
232 | |||
233 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
234 | if (elapsed_ns > genpd->power_on_latency_ns) { | ||
235 | genpd->power_on_latency_ns = elapsed_ns; | ||
236 | genpd->max_off_time_changed = true; | ||
237 | genpd_recalc_cpu_exit_latency(genpd); | ||
238 | if (genpd->name) | ||
239 | pr_warning("%s: Power-on latency exceeded, " | ||
240 | "new value %lld ns\n", genpd->name, | ||
241 | elapsed_ns); | ||
242 | } | ||
243 | } | ||
244 | 282 | ||
245 | out: | 283 | out: |
246 | genpd_set_active(genpd); | 284 | genpd_set_active(genpd); |
@@ -280,8 +318,6 @@ int pm_genpd_name_poweron(const char *domain_name) | |||
280 | return genpd ? pm_genpd_poweron(genpd) : -EINVAL; | 318 | return genpd ? pm_genpd_poweron(genpd) : -EINVAL; |
281 | } | 319 | } |
282 | 320 | ||
283 | #ifdef CONFIG_PM_RUNTIME | ||
284 | |||
285 | static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, | 321 | static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, |
286 | struct device *dev) | 322 | struct device *dev) |
287 | { | 323 | { |
@@ -544,16 +580,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
544 | } | 580 | } |
545 | 581 | ||
546 | if (genpd->power_off) { | 582 | if (genpd->power_off) { |
547 | ktime_t time_start; | ||
548 | s64 elapsed_ns; | ||
549 | |||
550 | if (atomic_read(&genpd->sd_count) > 0) { | 583 | if (atomic_read(&genpd->sd_count) > 0) { |
551 | ret = -EBUSY; | 584 | ret = -EBUSY; |
552 | goto out; | 585 | goto out; |
553 | } | 586 | } |
554 | 587 | ||
555 | time_start = ktime_get(); | ||
556 | |||
557 | /* | 588 | /* |
558 | * If sd_count > 0 at this point, one of the subdomains hasn't | 589 | * If sd_count > 0 at this point, one of the subdomains hasn't |
559 | * managed to call pm_genpd_poweron() for the master yet after | 590 | * managed to call pm_genpd_poweron() for the master yet after |
@@ -562,21 +593,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) | |||
562 | * the pm_genpd_poweron() restore power for us (this shouldn't | 593 | * the pm_genpd_poweron() restore power for us (this shouldn't |
563 | * happen very often). | 594 | * happen very often). |
564 | */ | 595 | */ |
565 | ret = genpd->power_off(genpd); | 596 | ret = genpd_power_off(genpd); |
566 | if (ret == -EBUSY) { | 597 | if (ret == -EBUSY) { |
567 | genpd_set_active(genpd); | 598 | genpd_set_active(genpd); |
568 | goto out; | 599 | goto out; |
569 | } | 600 | } |
570 | |||
571 | elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); | ||
572 | if (elapsed_ns > genpd->power_off_latency_ns) { | ||
573 | genpd->power_off_latency_ns = elapsed_ns; | ||
574 | genpd->max_off_time_changed = true; | ||
575 | if (genpd->name) | ||
576 | pr_warning("%s: Power-off latency exceeded, " | ||
577 | "new value %lld ns\n", genpd->name, | ||
578 | elapsed_ns); | ||
579 | } | ||
580 | } | 601 | } |
581 | 602 | ||
582 | genpd->status = GPD_STATE_POWER_OFF; | 603 | genpd->status = GPD_STATE_POWER_OFF; |
@@ -755,33 +776,15 @@ static int __init genpd_poweroff_unused(void) | |||
755 | } | 776 | } |
756 | late_initcall(genpd_poweroff_unused); | 777 | late_initcall(genpd_poweroff_unused); |
757 | 778 | ||
758 | #else | ||
759 | |||
760 | static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb, | ||
761 | unsigned long val, void *ptr) | ||
762 | { | ||
763 | return NOTIFY_DONE; | ||
764 | } | ||
765 | |||
766 | static inline void | ||
767 | genpd_queue_power_off_work(struct generic_pm_domain *genpd) {} | ||
768 | |||
769 | static inline void genpd_power_off_work_fn(struct work_struct *work) {} | ||
770 | |||
771 | #define pm_genpd_runtime_suspend NULL | ||
772 | #define pm_genpd_runtime_resume NULL | ||
773 | |||
774 | #endif /* CONFIG_PM_RUNTIME */ | ||
775 | |||
776 | #ifdef CONFIG_PM_SLEEP | 779 | #ifdef CONFIG_PM_SLEEP |
777 | 780 | ||
778 | /** | 781 | /** |
779 | * pm_genpd_present - Check if the given PM domain has been initialized. | 782 | * pm_genpd_present - Check if the given PM domain has been initialized. |
780 | * @genpd: PM domain to check. | 783 | * @genpd: PM domain to check. |
781 | */ | 784 | */ |
782 | static bool pm_genpd_present(struct generic_pm_domain *genpd) | 785 | static bool pm_genpd_present(const struct generic_pm_domain *genpd) |
783 | { | 786 | { |
784 | struct generic_pm_domain *gpd; | 787 | const struct generic_pm_domain *gpd; |
785 | 788 | ||
786 | if (IS_ERR_OR_NULL(genpd)) | 789 | if (IS_ERR_OR_NULL(genpd)) |
787 | return false; | 790 | return false; |
@@ -822,8 +825,7 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd) | |||
822 | || atomic_read(&genpd->sd_count) > 0) | 825 | || atomic_read(&genpd->sd_count) > 0) |
823 | return; | 826 | return; |
824 | 827 | ||
825 | if (genpd->power_off) | 828 | genpd_power_off(genpd); |
826 | genpd->power_off(genpd); | ||
827 | 829 | ||
828 | genpd->status = GPD_STATE_POWER_OFF; | 830 | genpd->status = GPD_STATE_POWER_OFF; |
829 | 831 | ||
@@ -854,8 +856,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd) | |||
854 | genpd_sd_counter_inc(link->master); | 856 | genpd_sd_counter_inc(link->master); |
855 | } | 857 | } |
856 | 858 | ||
857 | if (genpd->power_on) | 859 | genpd_power_on(genpd); |
858 | genpd->power_on(genpd); | ||
859 | 860 | ||
860 | genpd->status = GPD_STATE_ACTIVE; | 861 | genpd->status = GPD_STATE_ACTIVE; |
861 | } | 862 | } |
@@ -1277,8 +1278,7 @@ static int pm_genpd_restore_noirq(struct device *dev) | |||
1277 | * If the domain was off before the hibernation, make | 1278 | * If the domain was off before the hibernation, make |
1278 | * sure it will be off going forward. | 1279 | * sure it will be off going forward. |
1279 | */ | 1280 | */ |
1280 | if (genpd->power_off) | 1281 | genpd_power_off(genpd); |
1281 | genpd->power_off(genpd); | ||
1282 | 1282 | ||
1283 | return 0; | 1283 | return 0; |
1284 | } | 1284 | } |
@@ -1364,7 +1364,7 @@ void pm_genpd_syscore_poweron(struct device *dev) | |||
1364 | } | 1364 | } |
1365 | EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); | 1365 | EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); |
1366 | 1366 | ||
1367 | #else | 1367 | #else /* !CONFIG_PM_SLEEP */ |
1368 | 1368 | ||
1369 | #define pm_genpd_prepare NULL | 1369 | #define pm_genpd_prepare NULL |
1370 | #define pm_genpd_suspend NULL | 1370 | #define pm_genpd_suspend NULL |
@@ -1929,6 +1929,12 @@ void pm_genpd_init(struct generic_pm_domain *genpd, | |||
1929 | genpd->domain.ops.complete = pm_genpd_complete; | 1929 | genpd->domain.ops.complete = pm_genpd_complete; |
1930 | genpd->dev_ops.save_state = pm_genpd_default_save_state; | 1930 | genpd->dev_ops.save_state = pm_genpd_default_save_state; |
1931 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; | 1931 | genpd->dev_ops.restore_state = pm_genpd_default_restore_state; |
1932 | |||
1933 | if (genpd->flags & GENPD_FLAG_PM_CLK) { | ||
1934 | genpd->dev_ops.stop = pm_clk_suspend; | ||
1935 | genpd->dev_ops.start = pm_clk_resume; | ||
1936 | } | ||
1937 | |||
1932 | mutex_lock(&gpd_list_lock); | 1938 | mutex_lock(&gpd_list_lock); |
1933 | list_add(&genpd->gpd_list_node, &gpd_list); | 1939 | list_add(&genpd->gpd_list_node, &gpd_list); |
1934 | mutex_unlock(&gpd_list_lock); | 1940 | mutex_unlock(&gpd_list_lock); |
@@ -2216,11 +2222,12 @@ int genpd_dev_pm_attach(struct device *dev) | |||
2216 | } | 2222 | } |
2217 | 2223 | ||
2218 | dev->pm_domain->detach = genpd_dev_pm_detach; | 2224 | dev->pm_domain->detach = genpd_dev_pm_detach; |
2225 | pm_genpd_poweron(pd); | ||
2219 | 2226 | ||
2220 | return 0; | 2227 | return 0; |
2221 | } | 2228 | } |
2222 | EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); | 2229 | EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); |
2223 | #endif | 2230 | #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ |
2224 | 2231 | ||
2225 | 2232 | ||
2226 | /*** debugfs support ***/ | 2233 | /*** debugfs support ***/ |
@@ -2236,10 +2243,8 @@ static struct dentry *pm_genpd_debugfs_dir; | |||
2236 | 2243 | ||
2237 | /* | 2244 | /* |
2238 | * TODO: This function is a slightly modified version of rtpm_status_show | 2245 | * TODO: This function is a slightly modified version of rtpm_status_show |
2239 | * from sysfs.c, but dependencies between PM_GENERIC_DOMAINS and PM_RUNTIME | 2246 | * from sysfs.c, so generalize it. |
2240 | * are too loose to generalize it. | ||
2241 | */ | 2247 | */ |
2242 | #ifdef CONFIG_PM_RUNTIME | ||
2243 | static void rtpm_status_str(struct seq_file *s, struct device *dev) | 2248 | static void rtpm_status_str(struct seq_file *s, struct device *dev) |
2244 | { | 2249 | { |
2245 | static const char * const status_lookup[] = { | 2250 | static const char * const status_lookup[] = { |
@@ -2261,12 +2266,6 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev) | |||
2261 | 2266 | ||
2262 | seq_puts(s, p); | 2267 | seq_puts(s, p); |
2263 | } | 2268 | } |
2264 | #else | ||
2265 | static void rtpm_status_str(struct seq_file *s, struct device *dev) | ||
2266 | { | ||
2267 | seq_puts(s, "active"); | ||
2268 | } | ||
2269 | #endif | ||
2270 | 2269 | ||
2271 | static int pm_genpd_summary_one(struct seq_file *s, | 2270 | static int pm_genpd_summary_one(struct seq_file *s, |
2272 | struct generic_pm_domain *gpd) | 2271 | struct generic_pm_domain *gpd) |
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index d88a62e104d4..2a4154a09e4d 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c | |||
@@ -11,8 +11,6 @@ | |||
11 | #include <linux/pm_qos.h> | 11 | #include <linux/pm_qos.h> |
12 | #include <linux/hrtimer.h> | 12 | #include <linux/hrtimer.h> |
13 | 13 | ||
14 | #ifdef CONFIG_PM_RUNTIME | ||
15 | |||
16 | static int dev_update_qos_constraint(struct device *dev, void *data) | 14 | static int dev_update_qos_constraint(struct device *dev, void *data) |
17 | { | 15 | { |
18 | s64 *constraint_ns_p = data; | 16 | s64 *constraint_ns_p = data; |
@@ -227,15 +225,6 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain) | |||
227 | return false; | 225 | return false; |
228 | } | 226 | } |
229 | 227 | ||
230 | #else /* !CONFIG_PM_RUNTIME */ | ||
231 | |||
232 | static inline bool default_stop_ok(struct device *dev) { return false; } | ||
233 | |||
234 | #define default_power_down_ok NULL | ||
235 | #define always_on_power_down_ok NULL | ||
236 | |||
237 | #endif /* !CONFIG_PM_RUNTIME */ | ||
238 | |||
239 | struct dev_power_governor simple_qos_governor = { | 228 | struct dev_power_governor simple_qos_governor = { |
240 | .stop_ok = default_stop_ok, | 229 | .stop_ok = default_stop_ok, |
241 | .power_down_ok = default_power_down_ok, | 230 | .power_down_ok = default_power_down_ok, |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index a21223d95926..b6b8a273c5da 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -9,7 +9,7 @@ static inline void device_pm_init_common(struct device *dev) | |||
9 | } | 9 | } |
10 | } | 10 | } |
11 | 11 | ||
12 | #ifdef CONFIG_PM_RUNTIME | 12 | #ifdef CONFIG_PM |
13 | 13 | ||
14 | static inline void pm_runtime_early_init(struct device *dev) | 14 | static inline void pm_runtime_early_init(struct device *dev) |
15 | { | 15 | { |
@@ -20,7 +20,21 @@ static inline void pm_runtime_early_init(struct device *dev) | |||
20 | extern void pm_runtime_init(struct device *dev); | 20 | extern void pm_runtime_init(struct device *dev); |
21 | extern void pm_runtime_remove(struct device *dev); | 21 | extern void pm_runtime_remove(struct device *dev); |
22 | 22 | ||
23 | #else /* !CONFIG_PM_RUNTIME */ | 23 | /* |
24 | * sysfs.c | ||
25 | */ | ||
26 | |||
27 | extern int dpm_sysfs_add(struct device *dev); | ||
28 | extern void dpm_sysfs_remove(struct device *dev); | ||
29 | extern void rpm_sysfs_remove(struct device *dev); | ||
30 | extern int wakeup_sysfs_add(struct device *dev); | ||
31 | extern void wakeup_sysfs_remove(struct device *dev); | ||
32 | extern int pm_qos_sysfs_add_resume_latency(struct device *dev); | ||
33 | extern void pm_qos_sysfs_remove_resume_latency(struct device *dev); | ||
34 | extern int pm_qos_sysfs_add_flags(struct device *dev); | ||
35 | extern void pm_qos_sysfs_remove_flags(struct device *dev); | ||
36 | |||
37 | #else /* CONFIG_PM */ | ||
24 | 38 | ||
25 | static inline void pm_runtime_early_init(struct device *dev) | 39 | static inline void pm_runtime_early_init(struct device *dev) |
26 | { | 40 | { |
@@ -30,7 +44,15 @@ static inline void pm_runtime_early_init(struct device *dev) | |||
30 | static inline void pm_runtime_init(struct device *dev) {} | 44 | static inline void pm_runtime_init(struct device *dev) {} |
31 | static inline void pm_runtime_remove(struct device *dev) {} | 45 | static inline void pm_runtime_remove(struct device *dev) {} |
32 | 46 | ||
33 | #endif /* !CONFIG_PM_RUNTIME */ | 47 | static inline int dpm_sysfs_add(struct device *dev) { return 0; } |
48 | static inline void dpm_sysfs_remove(struct device *dev) {} | ||
49 | static inline void rpm_sysfs_remove(struct device *dev) {} | ||
50 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } | ||
51 | static inline void wakeup_sysfs_remove(struct device *dev) {} | ||
52 | static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } | ||
53 | static inline void pm_qos_sysfs_remove(struct device *dev) {} | ||
54 | |||
55 | #endif | ||
34 | 56 | ||
35 | #ifdef CONFIG_PM_SLEEP | 57 | #ifdef CONFIG_PM_SLEEP |
36 | 58 | ||
@@ -77,31 +99,3 @@ static inline void device_pm_init(struct device *dev) | |||
77 | device_pm_sleep_init(dev); | 99 | device_pm_sleep_init(dev); |
78 | pm_runtime_init(dev); | 100 | pm_runtime_init(dev); |
79 | } | 101 | } |
80 | |||
81 | #ifdef CONFIG_PM | ||
82 | |||
83 | /* | ||
84 | * sysfs.c | ||
85 | */ | ||
86 | |||
87 | extern int dpm_sysfs_add(struct device *dev); | ||
88 | extern void dpm_sysfs_remove(struct device *dev); | ||
89 | extern void rpm_sysfs_remove(struct device *dev); | ||
90 | extern int wakeup_sysfs_add(struct device *dev); | ||
91 | extern void wakeup_sysfs_remove(struct device *dev); | ||
92 | extern int pm_qos_sysfs_add_resume_latency(struct device *dev); | ||
93 | extern void pm_qos_sysfs_remove_resume_latency(struct device *dev); | ||
94 | extern int pm_qos_sysfs_add_flags(struct device *dev); | ||
95 | extern void pm_qos_sysfs_remove_flags(struct device *dev); | ||
96 | |||
97 | #else /* CONFIG_PM */ | ||
98 | |||
99 | static inline int dpm_sysfs_add(struct device *dev) { return 0; } | ||
100 | static inline void dpm_sysfs_remove(struct device *dev) {} | ||
101 | static inline void rpm_sysfs_remove(struct device *dev) {} | ||
102 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } | ||
103 | static inline void wakeup_sysfs_remove(struct device *dev) {} | ||
104 | static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } | ||
105 | static inline void pm_qos_sysfs_remove(struct device *dev) {} | ||
106 | |||
107 | #endif | ||
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 36b9eb4862cb..a8fe4c1a8d07 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c | |||
@@ -599,7 +599,6 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, | |||
599 | } | 599 | } |
600 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); | 600 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); |
601 | 601 | ||
602 | #ifdef CONFIG_PM_RUNTIME | ||
603 | static void __dev_pm_qos_drop_user_request(struct device *dev, | 602 | static void __dev_pm_qos_drop_user_request(struct device *dev, |
604 | enum dev_pm_qos_req_type type) | 603 | enum dev_pm_qos_req_type type) |
605 | { | 604 | { |
@@ -880,7 +879,3 @@ int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) | |||
880 | mutex_unlock(&dev_pm_qos_mtx); | 879 | mutex_unlock(&dev_pm_qos_mtx); |
881 | return ret; | 880 | return ret; |
882 | } | 881 | } |
883 | #else /* !CONFIG_PM_RUNTIME */ | ||
884 | static void __dev_pm_qos_hide_latency_limit(struct device *dev) {} | ||
885 | static void __dev_pm_qos_hide_flags(struct device *dev) {} | ||
886 | #endif /* CONFIG_PM_RUNTIME */ | ||
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 67c7938e430b..5070c4fe8542 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -13,43 +13,38 @@ | |||
13 | #include <trace/events/rpm.h> | 13 | #include <trace/events/rpm.h> |
14 | #include "power.h" | 14 | #include "power.h" |
15 | 15 | ||
16 | #define RPM_GET_CALLBACK(dev, cb) \ | 16 | typedef int (*pm_callback_t)(struct device *); |
17 | ({ \ | ||
18 | int (*__rpm_cb)(struct device *__d); \ | ||
19 | \ | ||
20 | if (dev->pm_domain) \ | ||
21 | __rpm_cb = dev->pm_domain->ops.cb; \ | ||
22 | else if (dev->type && dev->type->pm) \ | ||
23 | __rpm_cb = dev->type->pm->cb; \ | ||
24 | else if (dev->class && dev->class->pm) \ | ||
25 | __rpm_cb = dev->class->pm->cb; \ | ||
26 | else if (dev->bus && dev->bus->pm) \ | ||
27 | __rpm_cb = dev->bus->pm->cb; \ | ||
28 | else \ | ||
29 | __rpm_cb = NULL; \ | ||
30 | \ | ||
31 | if (!__rpm_cb && dev->driver && dev->driver->pm) \ | ||
32 | __rpm_cb = dev->driver->pm->cb; \ | ||
33 | \ | ||
34 | __rpm_cb; \ | ||
35 | }) | ||
36 | |||
37 | static int (*rpm_get_suspend_cb(struct device *dev))(struct device *) | ||
38 | { | ||
39 | return RPM_GET_CALLBACK(dev, runtime_suspend); | ||
40 | } | ||
41 | 17 | ||
42 | static int (*rpm_get_resume_cb(struct device *dev))(struct device *) | 18 | static pm_callback_t __rpm_get_callback(struct device *dev, size_t cb_offset) |
43 | { | 19 | { |
44 | return RPM_GET_CALLBACK(dev, runtime_resume); | 20 | pm_callback_t cb; |
45 | } | 21 | const struct dev_pm_ops *ops; |
22 | |||
23 | if (dev->pm_domain) | ||
24 | ops = &dev->pm_domain->ops; | ||
25 | else if (dev->type && dev->type->pm) | ||
26 | ops = dev->type->pm; | ||
27 | else if (dev->class && dev->class->pm) | ||
28 | ops = dev->class->pm; | ||
29 | else if (dev->bus && dev->bus->pm) | ||
30 | ops = dev->bus->pm; | ||
31 | else | ||
32 | ops = NULL; | ||
46 | 33 | ||
47 | #ifdef CONFIG_PM_RUNTIME | 34 | if (ops) |
48 | static int (*rpm_get_idle_cb(struct device *dev))(struct device *) | 35 | cb = *(pm_callback_t *)((void *)ops + cb_offset); |
49 | { | 36 | else |
50 | return RPM_GET_CALLBACK(dev, runtime_idle); | 37 | cb = NULL; |
38 | |||
39 | if (!cb && dev->driver && dev->driver->pm) | ||
40 | cb = *(pm_callback_t *)((void *)dev->driver->pm + cb_offset); | ||
41 | |||
42 | return cb; | ||
51 | } | 43 | } |
52 | 44 | ||
45 | #define RPM_GET_CALLBACK(dev, callback) \ | ||
46 | __rpm_get_callback(dev, offsetof(struct dev_pm_ops, callback)) | ||
47 | |||
53 | static int rpm_resume(struct device *dev, int rpmflags); | 48 | static int rpm_resume(struct device *dev, int rpmflags); |
54 | static int rpm_suspend(struct device *dev, int rpmflags); | 49 | static int rpm_suspend(struct device *dev, int rpmflags); |
55 | 50 | ||
@@ -347,7 +342,7 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
347 | 342 | ||
348 | dev->power.idle_notification = true; | 343 | dev->power.idle_notification = true; |
349 | 344 | ||
350 | callback = rpm_get_idle_cb(dev); | 345 | callback = RPM_GET_CALLBACK(dev, runtime_idle); |
351 | 346 | ||
352 | if (callback) | 347 | if (callback) |
353 | retval = __rpm_callback(callback, dev); | 348 | retval = __rpm_callback(callback, dev); |
@@ -517,7 +512,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
517 | 512 | ||
518 | __update_runtime_status(dev, RPM_SUSPENDING); | 513 | __update_runtime_status(dev, RPM_SUSPENDING); |
519 | 514 | ||
520 | callback = rpm_get_suspend_cb(dev); | 515 | callback = RPM_GET_CALLBACK(dev, runtime_suspend); |
521 | 516 | ||
522 | retval = rpm_callback(callback, dev); | 517 | retval = rpm_callback(callback, dev); |
523 | if (retval) | 518 | if (retval) |
@@ -737,7 +732,7 @@ static int rpm_resume(struct device *dev, int rpmflags) | |||
737 | 732 | ||
738 | __update_runtime_status(dev, RPM_RESUMING); | 733 | __update_runtime_status(dev, RPM_RESUMING); |
739 | 734 | ||
740 | callback = rpm_get_resume_cb(dev); | 735 | callback = RPM_GET_CALLBACK(dev, runtime_resume); |
741 | 736 | ||
742 | retval = rpm_callback(callback, dev); | 737 | retval = rpm_callback(callback, dev); |
743 | if (retval) { | 738 | if (retval) { |
@@ -1402,7 +1397,6 @@ void pm_runtime_remove(struct device *dev) | |||
1402 | if (dev->power.irq_safe && dev->parent) | 1397 | if (dev->power.irq_safe && dev->parent) |
1403 | pm_runtime_put(dev->parent); | 1398 | pm_runtime_put(dev->parent); |
1404 | } | 1399 | } |
1405 | #endif | ||
1406 | 1400 | ||
1407 | /** | 1401 | /** |
1408 | * pm_runtime_force_suspend - Force a device into suspend state if needed. | 1402 | * pm_runtime_force_suspend - Force a device into suspend state if needed. |
@@ -1422,16 +1416,10 @@ int pm_runtime_force_suspend(struct device *dev) | |||
1422 | int ret = 0; | 1416 | int ret = 0; |
1423 | 1417 | ||
1424 | pm_runtime_disable(dev); | 1418 | pm_runtime_disable(dev); |
1425 | |||
1426 | /* | ||
1427 | * Note that pm_runtime_status_suspended() returns false while | ||
1428 | * !CONFIG_PM_RUNTIME, which means the device will be put into low | ||
1429 | * power state. | ||
1430 | */ | ||
1431 | if (pm_runtime_status_suspended(dev)) | 1419 | if (pm_runtime_status_suspended(dev)) |
1432 | return 0; | 1420 | return 0; |
1433 | 1421 | ||
1434 | callback = rpm_get_suspend_cb(dev); | 1422 | callback = RPM_GET_CALLBACK(dev, runtime_suspend); |
1435 | 1423 | ||
1436 | if (!callback) { | 1424 | if (!callback) { |
1437 | ret = -ENOSYS; | 1425 | ret = -ENOSYS; |
@@ -1467,7 +1455,7 @@ int pm_runtime_force_resume(struct device *dev) | |||
1467 | int (*callback)(struct device *); | 1455 | int (*callback)(struct device *); |
1468 | int ret = 0; | 1456 | int ret = 0; |
1469 | 1457 | ||
1470 | callback = rpm_get_resume_cb(dev); | 1458 | callback = RPM_GET_CALLBACK(dev, runtime_resume); |
1471 | 1459 | ||
1472 | if (!callback) { | 1460 | if (!callback) { |
1473 | ret = -ENOSYS; | 1461 | ret = -ENOSYS; |
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index a9d26ed11bf4..d2be3f9c211c 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -95,7 +95,6 @@ | |||
95 | const char power_group_name[] = "power"; | 95 | const char power_group_name[] = "power"; |
96 | EXPORT_SYMBOL_GPL(power_group_name); | 96 | EXPORT_SYMBOL_GPL(power_group_name); |
97 | 97 | ||
98 | #ifdef CONFIG_PM_RUNTIME | ||
99 | static const char ctrl_auto[] = "auto"; | 98 | static const char ctrl_auto[] = "auto"; |
100 | static const char ctrl_on[] = "on"; | 99 | static const char ctrl_on[] = "on"; |
101 | 100 | ||
@@ -330,7 +329,6 @@ static ssize_t pm_qos_remote_wakeup_store(struct device *dev, | |||
330 | 329 | ||
331 | static DEVICE_ATTR(pm_qos_remote_wakeup, 0644, | 330 | static DEVICE_ATTR(pm_qos_remote_wakeup, 0644, |
332 | pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store); | 331 | pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store); |
333 | #endif /* CONFIG_PM_RUNTIME */ | ||
334 | 332 | ||
335 | #ifdef CONFIG_PM_SLEEP | 333 | #ifdef CONFIG_PM_SLEEP |
336 | static const char _enabled[] = "enabled"; | 334 | static const char _enabled[] = "enabled"; |
@@ -531,8 +529,6 @@ static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444, | |||
531 | #endif /* CONFIG_PM_SLEEP */ | 529 | #endif /* CONFIG_PM_SLEEP */ |
532 | 530 | ||
533 | #ifdef CONFIG_PM_ADVANCED_DEBUG | 531 | #ifdef CONFIG_PM_ADVANCED_DEBUG |
534 | #ifdef CONFIG_PM_RUNTIME | ||
535 | |||
536 | static ssize_t rtpm_usagecount_show(struct device *dev, | 532 | static ssize_t rtpm_usagecount_show(struct device *dev, |
537 | struct device_attribute *attr, char *buf) | 533 | struct device_attribute *attr, char *buf) |
538 | { | 534 | { |
@@ -562,10 +558,7 @@ static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL); | |||
562 | static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL); | 558 | static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL); |
563 | static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL); | 559 | static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL); |
564 | 560 | ||
565 | #endif | ||
566 | |||
567 | #ifdef CONFIG_PM_SLEEP | 561 | #ifdef CONFIG_PM_SLEEP |
568 | |||
569 | static ssize_t async_show(struct device *dev, struct device_attribute *attr, | 562 | static ssize_t async_show(struct device *dev, struct device_attribute *attr, |
570 | char *buf) | 563 | char *buf) |
571 | { | 564 | { |
@@ -595,7 +588,7 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr, | |||
595 | 588 | ||
596 | static DEVICE_ATTR(async, 0644, async_show, async_store); | 589 | static DEVICE_ATTR(async, 0644, async_show, async_store); |
597 | 590 | ||
598 | #endif | 591 | #endif /* CONFIG_PM_SLEEP */ |
599 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ | 592 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ |
600 | 593 | ||
601 | static struct attribute *power_attrs[] = { | 594 | static struct attribute *power_attrs[] = { |
@@ -603,12 +596,10 @@ static struct attribute *power_attrs[] = { | |||
603 | #ifdef CONFIG_PM_SLEEP | 596 | #ifdef CONFIG_PM_SLEEP |
604 | &dev_attr_async.attr, | 597 | &dev_attr_async.attr, |
605 | #endif | 598 | #endif |
606 | #ifdef CONFIG_PM_RUNTIME | ||
607 | &dev_attr_runtime_status.attr, | 599 | &dev_attr_runtime_status.attr, |
608 | &dev_attr_runtime_usage.attr, | 600 | &dev_attr_runtime_usage.attr, |
609 | &dev_attr_runtime_active_kids.attr, | 601 | &dev_attr_runtime_active_kids.attr, |
610 | &dev_attr_runtime_enabled.attr, | 602 | &dev_attr_runtime_enabled.attr, |
611 | #endif | ||
612 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ | 603 | #endif /* CONFIG_PM_ADVANCED_DEBUG */ |
613 | NULL, | 604 | NULL, |
614 | }; | 605 | }; |
@@ -640,7 +631,6 @@ static struct attribute_group pm_wakeup_attr_group = { | |||
640 | }; | 631 | }; |
641 | 632 | ||
642 | static struct attribute *runtime_attrs[] = { | 633 | static struct attribute *runtime_attrs[] = { |
643 | #ifdef CONFIG_PM_RUNTIME | ||
644 | #ifndef CONFIG_PM_ADVANCED_DEBUG | 634 | #ifndef CONFIG_PM_ADVANCED_DEBUG |
645 | &dev_attr_runtime_status.attr, | 635 | &dev_attr_runtime_status.attr, |
646 | #endif | 636 | #endif |
@@ -648,7 +638,6 @@ static struct attribute *runtime_attrs[] = { | |||
648 | &dev_attr_runtime_suspended_time.attr, | 638 | &dev_attr_runtime_suspended_time.attr, |
649 | &dev_attr_runtime_active_time.attr, | 639 | &dev_attr_runtime_active_time.attr, |
650 | &dev_attr_autosuspend_delay_ms.attr, | 640 | &dev_attr_autosuspend_delay_ms.attr, |
651 | #endif /* CONFIG_PM_RUNTIME */ | ||
652 | NULL, | 641 | NULL, |
653 | }; | 642 | }; |
654 | static struct attribute_group pm_runtime_attr_group = { | 643 | static struct attribute_group pm_runtime_attr_group = { |
@@ -657,9 +646,7 @@ static struct attribute_group pm_runtime_attr_group = { | |||
657 | }; | 646 | }; |
658 | 647 | ||
659 | static struct attribute *pm_qos_resume_latency_attrs[] = { | 648 | static struct attribute *pm_qos_resume_latency_attrs[] = { |
660 | #ifdef CONFIG_PM_RUNTIME | ||
661 | &dev_attr_pm_qos_resume_latency_us.attr, | 649 | &dev_attr_pm_qos_resume_latency_us.attr, |
662 | #endif /* CONFIG_PM_RUNTIME */ | ||
663 | NULL, | 650 | NULL, |
664 | }; | 651 | }; |
665 | static struct attribute_group pm_qos_resume_latency_attr_group = { | 652 | static struct attribute_group pm_qos_resume_latency_attr_group = { |
@@ -668,9 +655,7 @@ static struct attribute_group pm_qos_resume_latency_attr_group = { | |||
668 | }; | 655 | }; |
669 | 656 | ||
670 | static struct attribute *pm_qos_latency_tolerance_attrs[] = { | 657 | static struct attribute *pm_qos_latency_tolerance_attrs[] = { |
671 | #ifdef CONFIG_PM_RUNTIME | ||
672 | &dev_attr_pm_qos_latency_tolerance_us.attr, | 658 | &dev_attr_pm_qos_latency_tolerance_us.attr, |
673 | #endif /* CONFIG_PM_RUNTIME */ | ||
674 | NULL, | 659 | NULL, |
675 | }; | 660 | }; |
676 | static struct attribute_group pm_qos_latency_tolerance_attr_group = { | 661 | static struct attribute_group pm_qos_latency_tolerance_attr_group = { |
@@ -679,10 +664,8 @@ static struct attribute_group pm_qos_latency_tolerance_attr_group = { | |||
679 | }; | 664 | }; |
680 | 665 | ||
681 | static struct attribute *pm_qos_flags_attrs[] = { | 666 | static struct attribute *pm_qos_flags_attrs[] = { |
682 | #ifdef CONFIG_PM_RUNTIME | ||
683 | &dev_attr_pm_qos_no_power_off.attr, | 667 | &dev_attr_pm_qos_no_power_off.attr, |
684 | &dev_attr_pm_qos_remote_wakeup.attr, | 668 | &dev_attr_pm_qos_remote_wakeup.attr, |
685 | #endif /* CONFIG_PM_RUNTIME */ | ||
686 | NULL, | 669 | NULL, |
687 | }; | 670 | }; |
688 | static struct attribute_group pm_qos_flags_attr_group = { | 671 | static struct attribute_group pm_qos_flags_attr_group = { |
diff --git a/drivers/base/property.c b/drivers/base/property.c new file mode 100644 index 000000000000..c45845874d4f --- /dev/null +++ b/drivers/base/property.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * property.c - Unified device property interface. | ||
3 | * | ||
4 | * Copyright (C) 2014, Intel Corporation | ||
5 | * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
6 | * Mika Westerberg <mika.westerberg@linux.intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/property.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/acpi.h> | ||
16 | #include <linux/of.h> | ||
17 | |||
18 | /** | ||
19 | * device_property_present - check if a property of a device is present | ||
20 | * @dev: Device whose property is being checked | ||
21 | * @propname: Name of the property | ||
22 | * | ||
23 | * Check if property @propname is present in the device firmware description. | ||
24 | */ | ||
25 | bool device_property_present(struct device *dev, const char *propname) | ||
26 | { | ||
27 | if (IS_ENABLED(CONFIG_OF) && dev->of_node) | ||
28 | return of_property_read_bool(dev->of_node, propname); | ||
29 | |||
30 | return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL); | ||
31 | } | ||
32 | EXPORT_SYMBOL_GPL(device_property_present); | ||
33 | |||
34 | /** | ||
35 | * fwnode_property_present - check if a property of a firmware node is present | ||
36 | * @fwnode: Firmware node whose property to check | ||
37 | * @propname: Name of the property | ||
38 | */ | ||
39 | bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) | ||
40 | { | ||
41 | if (is_of_node(fwnode)) | ||
42 | return of_property_read_bool(of_node(fwnode), propname); | ||
43 | else if (is_acpi_node(fwnode)) | ||
44 | return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL); | ||
45 | |||
46 | return false; | ||
47 | } | ||
48 | EXPORT_SYMBOL_GPL(fwnode_property_present); | ||
49 | |||
50 | #define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ | ||
51 | (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ | ||
52 | : of_property_count_elems_of_size((node), (propname), sizeof(type)) | ||
53 | |||
54 | #define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \ | ||
55 | IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \ | ||
56 | (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \ | ||
57 | _val_, _nval_)) : \ | ||
58 | acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \ | ||
59 | _proptype_, _val_, _nval_) | ||
60 | |||
61 | /** | ||
62 | * device_property_read_u8_array - return a u8 array property of a device | ||
63 | * @dev: Device to get the property of | ||
64 | * @propname: Name of the property | ||
65 | * @val: The values are stored here | ||
66 | * @nval: Size of the @val array | ||
67 | * | ||
68 | * Function reads an array of u8 properties with @propname from the device | ||
69 | * firmware description and stores them to @val if found. | ||
70 | * | ||
71 | * Return: %0 if the property was found (success), | ||
72 | * %-EINVAL if given arguments are not valid, | ||
73 | * %-ENODATA if the property does not have a value, | ||
74 | * %-EPROTO if the property is not an array of numbers, | ||
75 | * %-EOVERFLOW if the size of the property is not as expected. | ||
76 | */ | ||
77 | int device_property_read_u8_array(struct device *dev, const char *propname, | ||
78 | u8 *val, size_t nval) | ||
79 | { | ||
80 | return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval); | ||
81 | } | ||
82 | EXPORT_SYMBOL_GPL(device_property_read_u8_array); | ||
83 | |||
84 | /** | ||
85 | * device_property_read_u16_array - return a u16 array property of a device | ||
86 | * @dev: Device to get the property of | ||
87 | * @propname: Name of the property | ||
88 | * @val: The values are stored here | ||
89 | * @nval: Size of the @val array | ||
90 | * | ||
91 | * Function reads an array of u16 properties with @propname from the device | ||
92 | * firmware description and stores them to @val if found. | ||
93 | * | ||
94 | * Return: %0 if the property was found (success), | ||
95 | * %-EINVAL if given arguments are not valid, | ||
96 | * %-ENODATA if the property does not have a value, | ||
97 | * %-EPROTO if the property is not an array of numbers, | ||
98 | * %-EOVERFLOW if the size of the property is not as expected. | ||
99 | */ | ||
100 | int device_property_read_u16_array(struct device *dev, const char *propname, | ||
101 | u16 *val, size_t nval) | ||
102 | { | ||
103 | return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval); | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(device_property_read_u16_array); | ||
106 | |||
107 | /** | ||
108 | * device_property_read_u32_array - return a u32 array property of a device | ||
109 | * @dev: Device to get the property of | ||
110 | * @propname: Name of the property | ||
111 | * @val: The values are stored here | ||
112 | * @nval: Size of the @val array | ||
113 | * | ||
114 | * Function reads an array of u32 properties with @propname from the device | ||
115 | * firmware description and stores them to @val if found. | ||
116 | * | ||
117 | * Return: %0 if the property was found (success), | ||
118 | * %-EINVAL if given arguments are not valid, | ||
119 | * %-ENODATA if the property does not have a value, | ||
120 | * %-EPROTO if the property is not an array of numbers, | ||
121 | * %-EOVERFLOW if the size of the property is not as expected. | ||
122 | */ | ||
123 | int device_property_read_u32_array(struct device *dev, const char *propname, | ||
124 | u32 *val, size_t nval) | ||
125 | { | ||
126 | return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval); | ||
127 | } | ||
128 | EXPORT_SYMBOL_GPL(device_property_read_u32_array); | ||
129 | |||
130 | /** | ||
131 | * device_property_read_u64_array - return a u64 array property of a device | ||
132 | * @dev: Device to get the property of | ||
133 | * @propname: Name of the property | ||
134 | * @val: The values are stored here | ||
135 | * @nval: Size of the @val array | ||
136 | * | ||
137 | * Function reads an array of u64 properties with @propname from the device | ||
138 | * firmware description and stores them to @val if found. | ||
139 | * | ||
140 | * Return: %0 if the property was found (success), | ||
141 | * %-EINVAL if given arguments are not valid, | ||
142 | * %-ENODATA if the property does not have a value, | ||
143 | * %-EPROTO if the property is not an array of numbers, | ||
144 | * %-EOVERFLOW if the size of the property is not as expected. | ||
145 | */ | ||
146 | int device_property_read_u64_array(struct device *dev, const char *propname, | ||
147 | u64 *val, size_t nval) | ||
148 | { | ||
149 | return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(device_property_read_u64_array); | ||
152 | |||
153 | /** | ||
154 | * device_property_read_string_array - return a string array property of device | ||
155 | * @dev: Device to get the property of | ||
156 | * @propname: Name of the property | ||
157 | * @val: The values are stored here | ||
158 | * @nval: Size of the @val array | ||
159 | * | ||
160 | * Function reads an array of string properties with @propname from the device | ||
161 | * firmware description and stores them to @val if found. | ||
162 | * | ||
163 | * Return: %0 if the property was found (success), | ||
164 | * %-EINVAL if given arguments are not valid, | ||
165 | * %-ENODATA if the property does not have a value, | ||
166 | * %-EPROTO or %-EILSEQ if the property is not an array of strings, | ||
167 | * %-EOVERFLOW if the size of the property is not as expected. | ||
168 | */ | ||
169 | int device_property_read_string_array(struct device *dev, const char *propname, | ||
170 | const char **val, size_t nval) | ||
171 | { | ||
172 | return IS_ENABLED(CONFIG_OF) && dev->of_node ? | ||
173 | of_property_read_string_array(dev->of_node, propname, val, nval) : | ||
174 | acpi_dev_prop_read(ACPI_COMPANION(dev), propname, | ||
175 | DEV_PROP_STRING, val, nval); | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(device_property_read_string_array); | ||
178 | |||
179 | /** | ||
180 | * device_property_read_string - return a string property of a device | ||
181 | * @dev: Device to get the property of | ||
182 | * @propname: Name of the property | ||
183 | * @val: The value is stored here | ||
184 | * | ||
185 | * Function reads property @propname from the device firmware description and | ||
186 | * stores the value into @val if found. The value is checked to be a string. | ||
187 | * | ||
188 | * Return: %0 if the property was found (success), | ||
189 | * %-EINVAL if given arguments are not valid, | ||
190 | * %-ENODATA if the property does not have a value, | ||
191 | * %-EPROTO or %-EILSEQ if the property type is not a string. | ||
192 | */ | ||
193 | int device_property_read_string(struct device *dev, const char *propname, | ||
194 | const char **val) | ||
195 | { | ||
196 | return IS_ENABLED(CONFIG_OF) && dev->of_node ? | ||
197 | of_property_read_string(dev->of_node, propname, val) : | ||
198 | acpi_dev_prop_read(ACPI_COMPANION(dev), propname, | ||
199 | DEV_PROP_STRING, val, 1); | ||
200 | } | ||
201 | EXPORT_SYMBOL_GPL(device_property_read_string); | ||
202 | |||
203 | #define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ | ||
204 | ({ \ | ||
205 | int _ret_; \ | ||
206 | if (is_of_node(_fwnode_)) \ | ||
207 | _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \ | ||
208 | _type_, _val_, _nval_); \ | ||
209 | else if (is_acpi_node(_fwnode_)) \ | ||
210 | _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \ | ||
211 | _proptype_, _val_, _nval_); \ | ||
212 | else \ | ||
213 | _ret_ = -ENXIO; \ | ||
214 | _ret_; \ | ||
215 | }) | ||
216 | |||
217 | /** | ||
218 | * fwnode_property_read_u8_array - return a u8 array property of firmware node | ||
219 | * @fwnode: Firmware node to get the property of | ||
220 | * @propname: Name of the property | ||
221 | * @val: The values are stored here | ||
222 | * @nval: Size of the @val array | ||
223 | * | ||
224 | * Read an array of u8 properties with @propname from @fwnode and stores them to | ||
225 | * @val if found. | ||
226 | * | ||
227 | * Return: %0 if the property was found (success), | ||
228 | * %-EINVAL if given arguments are not valid, | ||
229 | * %-ENODATA if the property does not have a value, | ||
230 | * %-EPROTO if the property is not an array of numbers, | ||
231 | * %-EOVERFLOW if the size of the property is not as expected, | ||
232 | * %-ENXIO if no suitable firmware interface is present. | ||
233 | */ | ||
234 | int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, | ||
235 | const char *propname, u8 *val, size_t nval) | ||
236 | { | ||
237 | return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8, | ||
238 | val, nval); | ||
239 | } | ||
240 | EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); | ||
241 | |||
242 | /** | ||
243 | * fwnode_property_read_u16_array - return a u16 array property of firmware node | ||
244 | * @fwnode: Firmware node to get the property of | ||
245 | * @propname: Name of the property | ||
246 | * @val: The values are stored here | ||
247 | * @nval: Size of the @val array | ||
248 | * | ||
249 | * Read an array of u16 properties with @propname from @fwnode and store them to | ||
250 | * @val if found. | ||
251 | * | ||
252 | * Return: %0 if the property was found (success), | ||
253 | * %-EINVAL if given arguments are not valid, | ||
254 | * %-ENODATA if the property does not have a value, | ||
255 | * %-EPROTO if the property is not an array of numbers, | ||
256 | * %-EOVERFLOW if the size of the property is not as expected, | ||
257 | * %-ENXIO if no suitable firmware interface is present. | ||
258 | */ | ||
259 | int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, | ||
260 | const char *propname, u16 *val, size_t nval) | ||
261 | { | ||
262 | return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16, | ||
263 | val, nval); | ||
264 | } | ||
265 | EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); | ||
266 | |||
267 | /** | ||
268 | * fwnode_property_read_u32_array - return a u32 array property of firmware node | ||
269 | * @fwnode: Firmware node to get the property of | ||
270 | * @propname: Name of the property | ||
271 | * @val: The values are stored here | ||
272 | * @nval: Size of the @val array | ||
273 | * | ||
274 | * Read an array of u32 properties with @propname from @fwnode store them to | ||
275 | * @val if found. | ||
276 | * | ||
277 | * Return: %0 if the property was found (success), | ||
278 | * %-EINVAL if given arguments are not valid, | ||
279 | * %-ENODATA if the property does not have a value, | ||
280 | * %-EPROTO if the property is not an array of numbers, | ||
281 | * %-EOVERFLOW if the size of the property is not as expected, | ||
282 | * %-ENXIO if no suitable firmware interface is present. | ||
283 | */ | ||
284 | int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, | ||
285 | const char *propname, u32 *val, size_t nval) | ||
286 | { | ||
287 | return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32, | ||
288 | val, nval); | ||
289 | } | ||
290 | EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); | ||
291 | |||
292 | /** | ||
293 | * fwnode_property_read_u64_array - return a u64 array property firmware node | ||
294 | * @fwnode: Firmware node to get the property of | ||
295 | * @propname: Name of the property | ||
296 | * @val: The values are stored here | ||
297 | * @nval: Size of the @val array | ||
298 | * | ||
299 | * Read an array of u64 properties with @propname from @fwnode and store them to | ||
300 | * @val if found. | ||
301 | * | ||
302 | * Return: %0 if the property was found (success), | ||
303 | * %-EINVAL if given arguments are not valid, | ||
304 | * %-ENODATA if the property does not have a value, | ||
305 | * %-EPROTO if the property is not an array of numbers, | ||
306 | * %-EOVERFLOW if the size of the property is not as expected, | ||
307 | * %-ENXIO if no suitable firmware interface is present. | ||
308 | */ | ||
309 | int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, | ||
310 | const char *propname, u64 *val, size_t nval) | ||
311 | { | ||
312 | return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64, | ||
313 | val, nval); | ||
314 | } | ||
315 | EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); | ||
316 | |||
317 | /** | ||
318 | * fwnode_property_read_string_array - return string array property of a node | ||
319 | * @fwnode: Firmware node to get the property of | ||
320 | * @propname: Name of the property | ||
321 | * @val: The values are stored here | ||
322 | * @nval: Size of the @val array | ||
323 | * | ||
324 | * Read an string list property @propname from the given firmware node and store | ||
325 | * them to @val if found. | ||
326 | * | ||
327 | * Return: %0 if the property was found (success), | ||
328 | * %-EINVAL if given arguments are not valid, | ||
329 | * %-ENODATA if the property does not have a value, | ||
330 | * %-EPROTO if the property is not an array of strings, | ||
331 | * %-EOVERFLOW if the size of the property is not as expected, | ||
332 | * %-ENXIO if no suitable firmware interface is present. | ||
333 | */ | ||
334 | int fwnode_property_read_string_array(struct fwnode_handle *fwnode, | ||
335 | const char *propname, const char **val, | ||
336 | size_t nval) | ||
337 | { | ||
338 | if (is_of_node(fwnode)) | ||
339 | return of_property_read_string_array(of_node(fwnode), propname, | ||
340 | val, nval); | ||
341 | else if (is_acpi_node(fwnode)) | ||
342 | return acpi_dev_prop_read(acpi_node(fwnode), propname, | ||
343 | DEV_PROP_STRING, val, nval); | ||
344 | |||
345 | return -ENXIO; | ||
346 | } | ||
347 | EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); | ||
348 | |||
349 | /** | ||
350 | * fwnode_property_read_string - return a string property of a firmware node | ||
351 | * @fwnode: Firmware node to get the property of | ||
352 | * @propname: Name of the property | ||
353 | * @val: The value is stored here | ||
354 | * | ||
355 | * Read property @propname from the given firmware node and store the value into | ||
356 | * @val if found. The value is checked to be a string. | ||
357 | * | ||
358 | * Return: %0 if the property was found (success), | ||
359 | * %-EINVAL if given arguments are not valid, | ||
360 | * %-ENODATA if the property does not have a value, | ||
361 | * %-EPROTO or %-EILSEQ if the property is not a string, | ||
362 | * %-ENXIO if no suitable firmware interface is present. | ||
363 | */ | ||
364 | int fwnode_property_read_string(struct fwnode_handle *fwnode, | ||
365 | const char *propname, const char **val) | ||
366 | { | ||
367 | if (is_of_node(fwnode)) | ||
368 | return of_property_read_string(of_node(fwnode),propname, val); | ||
369 | else if (is_acpi_node(fwnode)) | ||
370 | return acpi_dev_prop_read(acpi_node(fwnode), propname, | ||
371 | DEV_PROP_STRING, val, 1); | ||
372 | |||
373 | return -ENXIO; | ||
374 | } | ||
375 | EXPORT_SYMBOL_GPL(fwnode_property_read_string); | ||
376 | |||
377 | /** | ||
378 | * device_get_next_child_node - Return the next child node handle for a device | ||
379 | * @dev: Device to find the next child node for. | ||
380 | * @child: Handle to one of the device's child nodes or a null handle. | ||
381 | */ | ||
382 | struct fwnode_handle *device_get_next_child_node(struct device *dev, | ||
383 | struct fwnode_handle *child) | ||
384 | { | ||
385 | if (IS_ENABLED(CONFIG_OF) && dev->of_node) { | ||
386 | struct device_node *node; | ||
387 | |||
388 | node = of_get_next_available_child(dev->of_node, of_node(child)); | ||
389 | if (node) | ||
390 | return &node->fwnode; | ||
391 | } else if (IS_ENABLED(CONFIG_ACPI)) { | ||
392 | struct acpi_device *node; | ||
393 | |||
394 | node = acpi_get_next_child(dev, acpi_node(child)); | ||
395 | if (node) | ||
396 | return acpi_fwnode_handle(node); | ||
397 | } | ||
398 | return NULL; | ||
399 | } | ||
400 | EXPORT_SYMBOL_GPL(device_get_next_child_node); | ||
401 | |||
402 | /** | ||
403 | * fwnode_handle_put - Drop reference to a device node | ||
404 | * @fwnode: Pointer to the device node to drop the reference to. | ||
405 | * | ||
406 | * This has to be used when terminating device_for_each_child_node() iteration | ||
407 | * with break or return to prevent stale device node references from being left | ||
408 | * behind. | ||
409 | */ | ||
410 | void fwnode_handle_put(struct fwnode_handle *fwnode) | ||
411 | { | ||
412 | if (is_of_node(fwnode)) | ||
413 | of_node_put(of_node(fwnode)); | ||
414 | } | ||
415 | EXPORT_SYMBOL_GPL(fwnode_handle_put); | ||
416 | |||
417 | /** | ||
418 | * device_get_child_node_count - return the number of child nodes for device | ||
419 | * @dev: Device to cound the child nodes for | ||
420 | */ | ||
421 | unsigned int device_get_child_node_count(struct device *dev) | ||
422 | { | ||
423 | struct fwnode_handle *child; | ||
424 | unsigned int count = 0; | ||
425 | |||
426 | device_for_each_child_node(dev, child) | ||
427 | count++; | ||
428 | |||
429 | return count; | ||
430 | } | ||
431 | EXPORT_SYMBOL_GPL(device_get_child_node_count); | ||