b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From a9647655a2240148b7b6d29227dc76e9d6f12766 Mon Sep 17 00:00:00 2001 |
| 2 | From: Ran Wang <ran.wang_1@nxp.com> |
| 3 | Date: Thu, 24 Oct 2019 16:36:14 +0800 |
| 4 | Subject: [PATCH] PM: wakeup: Add routine to help fetch wakeup source object. |
| 5 | |
| 6 | Some user might want to go through all registered wakeup sources |
| 7 | and doing things accordingly. For example, SoC PM driver might need to |
| 8 | do HW programming to prevent powering down specific IP which wakeup |
| 9 | source depending on. So add this API to help walk through all registered |
| 10 | wakeup source objects on that list and return them one by one. |
| 11 | |
| 12 | Signed-off-by: Ran Wang <ran.wang_1@nxp.com> |
| 13 | Tested-by: Leonard Crestez <leonard.crestez@nxp.com> |
| 14 | Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| 15 | Acked-by: Anson Huang <Anson.Huang@nxp.com> |
| 16 | --- |
| 17 | drivers/base/power/wakeup.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ |
| 18 | include/linux/pm_wakeup.h | 9 ++++++++ |
| 19 | 2 files changed, 63 insertions(+) |
| 20 | |
| 21 | --- a/drivers/base/power/wakeup.c |
| 22 | +++ b/drivers/base/power/wakeup.c |
| 23 | @@ -251,6 +251,60 @@ void wakeup_source_unregister(struct wak |
| 24 | EXPORT_SYMBOL_GPL(wakeup_source_unregister); |
| 25 | |
| 26 | /** |
| 27 | + * wakeup_sources_read_lock - Lock wakeup source list for read. |
| 28 | + * |
| 29 | + * Returns an index of srcu lock for struct wakeup_srcu. |
| 30 | + * This index must be passed to the matching wakeup_sources_read_unlock(). |
| 31 | + */ |
| 32 | +int wakeup_sources_read_lock(void) |
| 33 | +{ |
| 34 | + return srcu_read_lock(&wakeup_srcu); |
| 35 | +} |
| 36 | +EXPORT_SYMBOL_GPL(wakeup_sources_read_lock); |
| 37 | + |
| 38 | +/** |
| 39 | + * wakeup_sources_read_unlock - Unlock wakeup source list. |
| 40 | + * @idx: return value from corresponding wakeup_sources_read_lock() |
| 41 | + */ |
| 42 | +void wakeup_sources_read_unlock(int idx) |
| 43 | +{ |
| 44 | + srcu_read_unlock(&wakeup_srcu, idx); |
| 45 | +} |
| 46 | +EXPORT_SYMBOL_GPL(wakeup_sources_read_unlock); |
| 47 | + |
| 48 | +/** |
| 49 | + * wakeup_sources_walk_start - Begin a walk on wakeup source list |
| 50 | + * |
| 51 | + * Returns first object of the list of wakeup sources. |
| 52 | + * |
| 53 | + * Note that to be safe, wakeup sources list needs to be locked by calling |
| 54 | + * wakeup_source_read_lock() for this. |
| 55 | + */ |
| 56 | +struct wakeup_source *wakeup_sources_walk_start(void) |
| 57 | +{ |
| 58 | + struct list_head *ws_head = &wakeup_sources; |
| 59 | + |
| 60 | + return list_entry_rcu(ws_head->next, struct wakeup_source, entry); |
| 61 | +} |
| 62 | +EXPORT_SYMBOL_GPL(wakeup_sources_walk_start); |
| 63 | + |
| 64 | +/** |
| 65 | + * wakeup_sources_walk_next - Get next wakeup source from the list |
| 66 | + * @ws: Previous wakeup source object |
| 67 | + * |
| 68 | + * Note that to be safe, wakeup sources list needs to be locked by calling |
| 69 | + * wakeup_source_read_lock() for this. |
| 70 | + */ |
| 71 | +struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws) |
| 72 | +{ |
| 73 | + struct list_head *ws_head = &wakeup_sources; |
| 74 | + |
| 75 | + return list_next_or_null_rcu(ws_head, &ws->entry, |
| 76 | + struct wakeup_source, entry); |
| 77 | +} |
| 78 | +EXPORT_SYMBOL_GPL(wakeup_sources_walk_next); |
| 79 | + |
| 80 | +/** |
| 81 | * device_wakeup_attach - Attach a wakeup source object to a device object. |
| 82 | * @dev: Device to handle. |
| 83 | * @ws: Wakeup source object to attach to @dev. |
| 84 | --- a/include/linux/pm_wakeup.h |
| 85 | +++ b/include/linux/pm_wakeup.h |
| 86 | @@ -63,6 +63,11 @@ struct wakeup_source { |
| 87 | bool autosleep_enabled:1; |
| 88 | }; |
| 89 | |
| 90 | +#define for_each_wakeup_source(ws) \ |
| 91 | + for ((ws) = wakeup_sources_walk_start(); \ |
| 92 | + (ws); \ |
| 93 | + (ws) = wakeup_sources_walk_next((ws))) |
| 94 | + |
| 95 | #ifdef CONFIG_PM_SLEEP |
| 96 | |
| 97 | /* |
| 98 | @@ -92,6 +97,10 @@ extern void wakeup_source_remove(struct |
| 99 | extern struct wakeup_source *wakeup_source_register(struct device *dev, |
| 100 | const char *name); |
| 101 | extern void wakeup_source_unregister(struct wakeup_source *ws); |
| 102 | +extern int wakeup_sources_read_lock(void); |
| 103 | +extern void wakeup_sources_read_unlock(int idx); |
| 104 | +extern struct wakeup_source *wakeup_sources_walk_start(void); |
| 105 | +extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws); |
| 106 | extern int device_wakeup_enable(struct device *dev); |
| 107 | extern int device_wakeup_disable(struct device *dev); |
| 108 | extern void device_set_wakeup_capable(struct device *dev, bool capable); |