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