Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/power/wakeirq.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0
2
/* Device wakeirq helper functions */
3
#include <linux/device.h>
4
#include <linux/interrupt.h>
5
#include <linux/irq.h>
6
#include <linux/slab.h>
7
#include <linux/pm_runtime.h>
8
#include <linux/pm_wakeirq.h>
9
10
#include "power.h"
11
12
/**
13
* dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
14
* @dev: Device entry
15
* @wirq: Wake irq specific data
16
*
17
* Internal function to attach a dedicated wake-up interrupt as a wake IRQ.
18
*/
19
static int dev_pm_attach_wake_irq(struct device *dev, struct wake_irq *wirq)
20
{
21
unsigned long flags;
22
23
if (!dev || !wirq)
24
return -EINVAL;
25
26
spin_lock_irqsave(&dev->power.lock, flags);
27
if (dev_WARN_ONCE(dev, dev->power.wakeirq,
28
"wake irq already initialized\n")) {
29
spin_unlock_irqrestore(&dev->power.lock, flags);
30
return -EEXIST;
31
}
32
33
dev->power.wakeirq = wirq;
34
device_wakeup_attach_irq(dev, wirq);
35
36
spin_unlock_irqrestore(&dev->power.lock, flags);
37
return 0;
38
}
39
40
/**
41
* dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
42
* @dev: Device entry
43
* @irq: Device IO interrupt
44
*
45
* Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
46
* automatically configured for wake-up from suspend based
47
* on the device specific sysfs wakeup entry. Typically called
48
* during driver probe after calling device_init_wakeup().
49
*/
50
int dev_pm_set_wake_irq(struct device *dev, int irq)
51
{
52
struct wake_irq *wirq;
53
int err;
54
55
if (irq < 0)
56
return -EINVAL;
57
58
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
59
if (!wirq)
60
return -ENOMEM;
61
62
wirq->dev = dev;
63
wirq->irq = irq;
64
65
err = dev_pm_attach_wake_irq(dev, wirq);
66
if (err)
67
kfree(wirq);
68
69
return err;
70
}
71
EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
72
73
/**
74
* dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
75
* @dev: Device entry
76
*
77
* Detach a device wake IRQ and free resources.
78
*
79
* Note that it's OK for drivers to call this without calling
80
* dev_pm_set_wake_irq() as all the driver instances may not have
81
* a wake IRQ configured. This avoid adding wake IRQ specific
82
* checks into the drivers.
83
*/
84
void dev_pm_clear_wake_irq(struct device *dev)
85
{
86
struct wake_irq *wirq = dev->power.wakeirq;
87
unsigned long flags;
88
89
if (!wirq)
90
return;
91
92
spin_lock_irqsave(&dev->power.lock, flags);
93
device_wakeup_detach_irq(dev);
94
dev->power.wakeirq = NULL;
95
spin_unlock_irqrestore(&dev->power.lock, flags);
96
97
if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) {
98
free_irq(wirq->irq, wirq);
99
wirq->status &= ~WAKE_IRQ_DEDICATED_MASK;
100
}
101
kfree(wirq->name);
102
kfree(wirq);
103
}
104
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
105
106
static void devm_pm_clear_wake_irq(void *dev)
107
{
108
dev_pm_clear_wake_irq(dev);
109
}
110
111
/**
112
* devm_pm_set_wake_irq - device-managed variant of dev_pm_set_wake_irq
113
* @dev: Device entry
114
* @irq: Device IO interrupt
115
*
116
*
117
* Attach a device IO interrupt as a wake IRQ, same with dev_pm_set_wake_irq,
118
* but the device will be auto clear wake capability on driver detach.
119
*/
120
int devm_pm_set_wake_irq(struct device *dev, int irq)
121
{
122
int ret;
123
124
ret = dev_pm_set_wake_irq(dev, irq);
125
if (ret)
126
return ret;
127
128
return devm_add_action_or_reset(dev, devm_pm_clear_wake_irq, dev);
129
}
130
EXPORT_SYMBOL_GPL(devm_pm_set_wake_irq);
131
132
/**
133
* handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
134
* @irq: Device specific dedicated wake-up interrupt
135
* @_wirq: Wake IRQ data
136
*
137
* Some devices have a separate wake-up interrupt in addition to the
138
* device IO interrupt. The wake-up interrupt signals that a device
139
* should be woken up from it's idle state. This handler uses device
140
* specific pm_runtime functions to wake the device, and then it's
141
* up to the device to do whatever it needs to. Note that as the
142
* device may need to restore context and start up regulators, we
143
* use a threaded IRQ.
144
*
145
* Also note that we are not resending the lost device interrupts.
146
* We assume that the wake-up interrupt just needs to wake-up the
147
* device, and then device's pm_runtime_resume() can deal with the
148
* situation.
149
*/
150
static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
151
{
152
struct wake_irq *wirq = _wirq;
153
int res;
154
155
/* Maybe abort suspend? */
156
if (irqd_is_wakeup_set(irq_get_irq_data(irq))) {
157
pm_wakeup_event(wirq->dev, 0);
158
159
return IRQ_HANDLED;
160
}
161
162
/* We don't want RPM_ASYNC or RPM_NOWAIT here */
163
res = pm_runtime_resume(wirq->dev);
164
if (res < 0)
165
dev_warn(wirq->dev,
166
"wake IRQ with no resume: %i\n", res);
167
168
return IRQ_HANDLED;
169
}
170
171
static int __dev_pm_set_dedicated_wake_irq(struct device *dev, int irq, unsigned int flag)
172
{
173
struct wake_irq *wirq;
174
int err;
175
176
if (irq < 0)
177
return -EINVAL;
178
179
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
180
if (!wirq)
181
return -ENOMEM;
182
183
wirq->name = kasprintf(GFP_KERNEL, "%s:wakeup", dev_name(dev));
184
if (!wirq->name) {
185
err = -ENOMEM;
186
goto err_free;
187
}
188
189
wirq->dev = dev;
190
wirq->irq = irq;
191
192
/* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
193
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
194
195
/*
196
* Consumer device may need to power up and restore state
197
* so we use a threaded irq.
198
*/
199
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
200
IRQF_ONESHOT | IRQF_NO_AUTOEN,
201
wirq->name, wirq);
202
if (err)
203
goto err_free_name;
204
205
err = dev_pm_attach_wake_irq(dev, wirq);
206
if (err)
207
goto err_free_irq;
208
209
wirq->status = WAKE_IRQ_DEDICATED_ALLOCATED | flag;
210
211
return err;
212
213
err_free_irq:
214
free_irq(irq, wirq);
215
err_free_name:
216
kfree(wirq->name);
217
err_free:
218
kfree(wirq);
219
220
return err;
221
}
222
223
/**
224
* dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
225
* @dev: Device entry
226
* @irq: Device wake-up interrupt
227
*
228
* Unless your hardware has separate wake-up interrupts in addition
229
* to the device IO interrupts, you don't need this.
230
*
231
* Sets up a threaded interrupt handler for a device that has
232
* a dedicated wake-up interrupt in addition to the device IO
233
* interrupt.
234
*/
235
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
236
{
237
return __dev_pm_set_dedicated_wake_irq(dev, irq, 0);
238
}
239
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
240
241
/**
242
* dev_pm_set_dedicated_wake_irq_reverse - Request a dedicated wake-up interrupt
243
* with reverse enable ordering
244
* @dev: Device entry
245
* @irq: Device wake-up interrupt
246
*
247
* Unless your hardware has separate wake-up interrupts in addition
248
* to the device IO interrupts, you don't need this.
249
*
250
* Sets up a threaded interrupt handler for a device that has a dedicated
251
* wake-up interrupt in addition to the device IO interrupt. It sets
252
* the status of WAKE_IRQ_DEDICATED_REVERSE to tell rpm_suspend()
253
* to enable dedicated wake-up interrupt after running the runtime suspend
254
* callback for @dev.
255
*/
256
int dev_pm_set_dedicated_wake_irq_reverse(struct device *dev, int irq)
257
{
258
return __dev_pm_set_dedicated_wake_irq(dev, irq, WAKE_IRQ_DEDICATED_REVERSE);
259
}
260
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq_reverse);
261
262
/**
263
* dev_pm_enable_wake_irq_check - Checks and enables wake-up interrupt
264
* @dev: Device
265
* @can_change_status: Can change wake-up interrupt status
266
*
267
* Enables wakeirq conditionally. We need to enable wake-up interrupt
268
* lazily on the first rpm_suspend(). This is needed as the consumer device
269
* starts in RPM_SUSPENDED state, and the first pm_runtime_get() would
270
* otherwise try to disable already disabled wakeirq. The wake-up interrupt
271
* starts disabled with IRQ_NOAUTOEN set.
272
*
273
* Should be only called from rpm_suspend() and rpm_resume() path.
274
* Caller must hold &dev->power.lock to change wirq->status
275
*/
276
void dev_pm_enable_wake_irq_check(struct device *dev,
277
bool can_change_status)
278
{
279
struct wake_irq *wirq = dev->power.wakeirq;
280
281
if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK))
282
return;
283
284
if (likely(wirq->status & WAKE_IRQ_DEDICATED_MANAGED)) {
285
goto enable;
286
} else if (can_change_status) {
287
wirq->status |= WAKE_IRQ_DEDICATED_MANAGED;
288
goto enable;
289
}
290
291
return;
292
293
enable:
294
if (!can_change_status || !(wirq->status & WAKE_IRQ_DEDICATED_REVERSE)) {
295
enable_irq(wirq->irq);
296
wirq->status |= WAKE_IRQ_DEDICATED_ENABLED;
297
}
298
}
299
300
/**
301
* dev_pm_disable_wake_irq_check - Checks and disables wake-up interrupt
302
* @dev: Device
303
* @cond_disable: if set, also check WAKE_IRQ_DEDICATED_REVERSE
304
*
305
* Disables wake-up interrupt conditionally based on status.
306
* Should be only called from rpm_suspend() and rpm_resume() path.
307
*/
308
void dev_pm_disable_wake_irq_check(struct device *dev, bool cond_disable)
309
{
310
struct wake_irq *wirq = dev->power.wakeirq;
311
312
if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK))
313
return;
314
315
if (cond_disable && (wirq->status & WAKE_IRQ_DEDICATED_REVERSE))
316
return;
317
318
if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED) {
319
wirq->status &= ~WAKE_IRQ_DEDICATED_ENABLED;
320
disable_irq_nosync(wirq->irq);
321
}
322
}
323
324
/**
325
* dev_pm_enable_wake_irq_complete - enable wake IRQ not enabled before
326
* @dev: Device using the wake IRQ
327
*
328
* Enable wake IRQ conditionally based on status, mainly used if want to
329
* enable wake IRQ after running ->runtime_suspend() which depends on
330
* WAKE_IRQ_DEDICATED_REVERSE.
331
*
332
* Should be only called from rpm_suspend() path.
333
*/
334
void dev_pm_enable_wake_irq_complete(struct device *dev)
335
{
336
struct wake_irq *wirq = dev->power.wakeirq;
337
338
if (!wirq || !(wirq->status & WAKE_IRQ_DEDICATED_MASK))
339
return;
340
341
if (wirq->status & WAKE_IRQ_DEDICATED_MANAGED &&
342
wirq->status & WAKE_IRQ_DEDICATED_REVERSE) {
343
enable_irq(wirq->irq);
344
wirq->status |= WAKE_IRQ_DEDICATED_ENABLED;
345
}
346
}
347
348
/**
349
* dev_pm_arm_wake_irq - Arm device wake-up
350
* @wirq: Device wake-up interrupt
351
*
352
* Sets up the wake-up event conditionally based on the
353
* device_may_wake().
354
*/
355
void dev_pm_arm_wake_irq(struct wake_irq *wirq)
356
{
357
if (!wirq)
358
return;
359
360
if (device_may_wakeup(wirq->dev)) {
361
if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
362
!(wirq->status & WAKE_IRQ_DEDICATED_ENABLED))
363
enable_irq(wirq->irq);
364
365
enable_irq_wake(wirq->irq);
366
}
367
}
368
369
/**
370
* dev_pm_disarm_wake_irq - Disarm device wake-up
371
* @wirq: Device wake-up interrupt
372
*
373
* Clears up the wake-up event conditionally based on the
374
* device_may_wake().
375
*/
376
void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
377
{
378
if (!wirq)
379
return;
380
381
if (device_may_wakeup(wirq->dev)) {
382
disable_irq_wake(wirq->irq);
383
384
if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
385
!(wirq->status & WAKE_IRQ_DEDICATED_ENABLED))
386
disable_irq_nosync(wirq->irq);
387
}
388
}
389
390