wakeirq.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * wakeirq.c - Device wakeirq helper functions
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  9. * kind, whether express or implied; without even the implied warranty
  10. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <linux/device.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/irq.h>
  16. #include <linux/slab.h>
  17. #include <linux/pm_runtime.h>
  18. #include <linux/pm_wakeirq.h>
  19. #include "power.h"
  20. /**
  21. * dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
  22. * @dev: Device entry
  23. * @irq: Device wake-up capable interrupt
  24. * @wirq: Wake irq specific data
  25. *
  26. * Internal function to attach either a device IO interrupt or a
  27. * dedicated wake-up interrupt as a wake IRQ.
  28. */
  29. static int dev_pm_attach_wake_irq(struct device *dev, int irq,
  30. struct wake_irq *wirq)
  31. {
  32. unsigned long flags;
  33. int err;
  34. if (!dev || !wirq)
  35. return -EINVAL;
  36. spin_lock_irqsave(&dev->power.lock, flags);
  37. if (dev_WARN_ONCE(dev, dev->power.wakeirq,
  38. "wake irq already initialized\n")) {
  39. spin_unlock_irqrestore(&dev->power.lock, flags);
  40. return -EEXIST;
  41. }
  42. err = device_wakeup_attach_irq(dev, wirq);
  43. if (!err)
  44. dev->power.wakeirq = wirq;
  45. spin_unlock_irqrestore(&dev->power.lock, flags);
  46. return err;
  47. }
  48. /**
  49. * dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
  50. * @dev: Device entry
  51. * @irq: Device IO interrupt
  52. *
  53. * Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
  54. * automatically configured for wake-up from suspend based
  55. * on the device specific sysfs wakeup entry. Typically called
  56. * during driver probe after calling device_init_wakeup().
  57. */
  58. int dev_pm_set_wake_irq(struct device *dev, int irq)
  59. {
  60. struct wake_irq *wirq;
  61. int err;
  62. if (irq < 0)
  63. return -EINVAL;
  64. wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
  65. if (!wirq)
  66. return -ENOMEM;
  67. wirq->dev = dev;
  68. wirq->irq = irq;
  69. err = dev_pm_attach_wake_irq(dev, irq, wirq);
  70. if (err)
  71. kfree(wirq);
  72. return err;
  73. }
  74. EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
  75. /**
  76. * dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
  77. * @dev: Device entry
  78. *
  79. * Detach a device wake IRQ and free resources.
  80. *
  81. * Note that it's OK for drivers to call this without calling
  82. * dev_pm_set_wake_irq() as all the driver instances may not have
  83. * a wake IRQ configured. This avoid adding wake IRQ specific
  84. * checks into the drivers.
  85. */
  86. void dev_pm_clear_wake_irq(struct device *dev)
  87. {
  88. struct wake_irq *wirq = dev->power.wakeirq;
  89. unsigned long flags;
  90. if (!wirq)
  91. return;
  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. if (wirq->dedicated_irq)
  97. free_irq(wirq->irq, wirq);
  98. kfree(wirq);
  99. }
  100. EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
  101. /**
  102. * handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
  103. * @irq: Device specific dedicated wake-up interrupt
  104. * @_wirq: Wake IRQ data
  105. *
  106. * Some devices have a separate wake-up interrupt in addition to the
  107. * device IO interrupt. The wake-up interrupt signals that a device
  108. * should be woken up from it's idle state. This handler uses device
  109. * specific pm_runtime functions to wake the device, and then it's
  110. * up to the device to do whatever it needs to. Note that as the
  111. * device may need to restore context and start up regulators, we
  112. * use a threaded IRQ.
  113. *
  114. * Also note that we are not resending the lost device interrupts.
  115. * We assume that the wake-up interrupt just needs to wake-up the
  116. * device, and then device's pm_runtime_resume() can deal with the
  117. * situation.
  118. */
  119. static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
  120. {
  121. struct wake_irq *wirq = _wirq;
  122. int res;
  123. /* We don't want RPM_ASYNC or RPM_NOWAIT here */
  124. res = pm_runtime_resume(wirq->dev);
  125. if (res < 0)
  126. dev_warn(wirq->dev,
  127. "wake IRQ with no resume: %i\n", res);
  128. return IRQ_HANDLED;
  129. }
  130. /**
  131. * dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
  132. * @dev: Device entry
  133. * @irq: Device wake-up interrupt
  134. *
  135. * Unless your hardware has separate wake-up interrupts in addition
  136. * to the device IO interrupts, you don't need this.
  137. *
  138. * Sets up a threaded interrupt handler for a device that has
  139. * a dedicated wake-up interrupt in addition to the device IO
  140. * interrupt.
  141. *
  142. * The interrupt starts disabled, and needs to be managed for
  143. * the device by the bus code or the device driver using
  144. * dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
  145. * functions.
  146. */
  147. int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
  148. {
  149. struct wake_irq *wirq;
  150. int err;
  151. if (irq < 0)
  152. return -EINVAL;
  153. wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
  154. if (!wirq)
  155. return -ENOMEM;
  156. wirq->dev = dev;
  157. wirq->irq = irq;
  158. wirq->dedicated_irq = true;
  159. irq_set_status_flags(irq, IRQ_NOAUTOEN);
  160. /*
  161. * Consumer device may need to power up and restore state
  162. * so we use a threaded irq.
  163. */
  164. err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
  165. IRQF_ONESHOT, dev_name(dev), wirq);
  166. if (err)
  167. goto err_free;
  168. err = dev_pm_attach_wake_irq(dev, irq, wirq);
  169. if (err)
  170. goto err_free_irq;
  171. return err;
  172. err_free_irq:
  173. free_irq(irq, wirq);
  174. err_free:
  175. kfree(wirq);
  176. return err;
  177. }
  178. EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
  179. /**
  180. * dev_pm_enable_wake_irq - Enable device wake-up interrupt
  181. * @dev: Device
  182. *
  183. * Called from the bus code or the device driver for
  184. * runtime_suspend() to enable the wake-up interrupt while
  185. * the device is running.
  186. *
  187. * Note that for runtime_suspend()) the wake-up interrupts
  188. * should be unconditionally enabled unlike for suspend()
  189. * that is conditional.
  190. */
  191. void dev_pm_enable_wake_irq(struct device *dev)
  192. {
  193. struct wake_irq *wirq = dev->power.wakeirq;
  194. if (wirq && wirq->dedicated_irq)
  195. enable_irq(wirq->irq);
  196. }
  197. EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
  198. /**
  199. * dev_pm_disable_wake_irq - Disable device wake-up interrupt
  200. * @dev: Device
  201. *
  202. * Called from the bus code or the device driver for
  203. * runtime_resume() to disable the wake-up interrupt while
  204. * the device is running.
  205. */
  206. void dev_pm_disable_wake_irq(struct device *dev)
  207. {
  208. struct wake_irq *wirq = dev->power.wakeirq;
  209. if (wirq && wirq->dedicated_irq)
  210. disable_irq_nosync(wirq->irq);
  211. }
  212. EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
  213. /**
  214. * dev_pm_arm_wake_irq - Arm device wake-up
  215. * @wirq: Device wake-up interrupt
  216. *
  217. * Sets up the wake-up event conditionally based on the
  218. * device_may_wake().
  219. */
  220. void dev_pm_arm_wake_irq(struct wake_irq *wirq)
  221. {
  222. if (!wirq)
  223. return;
  224. if (device_may_wakeup(wirq->dev))
  225. enable_irq_wake(wirq->irq);
  226. }
  227. /**
  228. * dev_pm_disarm_wake_irq - Disarm device wake-up
  229. * @wirq: Device wake-up interrupt
  230. *
  231. * Clears up the wake-up event conditionally based on the
  232. * device_may_wake().
  233. */
  234. void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
  235. {
  236. if (!wirq)
  237. return;
  238. if (device_may_wakeup(wirq->dev))
  239. disable_irq_wake(wirq->irq);
  240. }