otg-wakelock.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * otg-wakelock.c
  3. *
  4. * Copyright (C) 2011 Google, Inc.
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/device.h>
  18. #include <linux/err.h>
  19. #include <linux/module.h>
  20. #include <linux/notifier.h>
  21. #include <linux/wakelock.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/usb/otg.h>
  24. #define TEMPORARY_HOLD_TIME 2000
  25. static bool enabled = true;
  26. static struct usb_phy *otgwl_xceiv;
  27. static struct notifier_block otgwl_nb;
  28. /*
  29. * otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the
  30. * held field is updated to match.
  31. */
  32. static DEFINE_SPINLOCK(otgwl_spinlock);
  33. /*
  34. * Only one lock, but since these 3 fields are associated with each other...
  35. */
  36. struct otgwl_lock {
  37. char name[40];
  38. struct wake_lock wakelock;
  39. bool held;
  40. };
  41. /*
  42. * VBUS present lock. Also used as a timed lock on charger
  43. * connect/disconnect and USB host disconnect, to allow the system
  44. * to react to the change in power.
  45. */
  46. static struct otgwl_lock vbus_lock;
  47. static void otgwl_hold(struct otgwl_lock *lock)
  48. {
  49. if (!lock->held) {
  50. wake_lock(&lock->wakelock);
  51. lock->held = true;
  52. }
  53. }
  54. static void otgwl_temporary_hold(struct otgwl_lock *lock)
  55. {
  56. wake_lock_timeout(&lock->wakelock,
  57. msecs_to_jiffies(TEMPORARY_HOLD_TIME));
  58. lock->held = false;
  59. }
  60. static void otgwl_drop(struct otgwl_lock *lock)
  61. {
  62. if (lock->held) {
  63. wake_unlock(&lock->wakelock);
  64. lock->held = false;
  65. }
  66. }
  67. static void otgwl_handle_event(unsigned long event)
  68. {
  69. unsigned long irqflags;
  70. spin_lock_irqsave(&otgwl_spinlock, irqflags);
  71. if (!enabled) {
  72. otgwl_drop(&vbus_lock);
  73. spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
  74. return;
  75. }
  76. switch (event) {
  77. case USB_EVENT_VBUS:
  78. case USB_EVENT_ENUMERATED:
  79. otgwl_hold(&vbus_lock);
  80. break;
  81. case USB_EVENT_NONE:
  82. case USB_EVENT_ID:
  83. case USB_EVENT_CHARGER:
  84. otgwl_temporary_hold(&vbus_lock);
  85. break;
  86. default:
  87. break;
  88. }
  89. spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
  90. }
  91. static int otgwl_otg_notifications(struct notifier_block *nb,
  92. unsigned long event, void *unused)
  93. {
  94. otgwl_handle_event(event);
  95. return NOTIFY_OK;
  96. }
  97. static int set_enabled(const char *val, const struct kernel_param *kp)
  98. {
  99. int rv = param_set_bool(val, kp);
  100. if (rv)
  101. return rv;
  102. if (otgwl_xceiv)
  103. otgwl_handle_event(otgwl_xceiv->last_event);
  104. return 0;
  105. }
  106. static struct kernel_param_ops enabled_param_ops = {
  107. .set = set_enabled,
  108. .get = param_get_bool,
  109. };
  110. module_param_cb(enabled, &enabled_param_ops, &enabled, 0644);
  111. MODULE_PARM_DESC(enabled, "enable wakelock when VBUS present");
  112. static int __init otg_wakelock_init(void)
  113. {
  114. int ret;
  115. struct usb_phy *phy;
  116. phy = usb_get_phy(USB_PHY_TYPE_USB2);
  117. if (IS_ERR(phy)) {
  118. pr_err("%s: No USB transceiver found\n", __func__);
  119. return PTR_ERR(phy);
  120. }
  121. otgwl_xceiv = phy;
  122. snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s",
  123. dev_name(otgwl_xceiv->dev));
  124. wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND,
  125. vbus_lock.name);
  126. otgwl_nb.notifier_call = otgwl_otg_notifications;
  127. ret = usb_register_notifier(otgwl_xceiv, &otgwl_nb);
  128. if (ret) {
  129. pr_err("%s: usb_register_notifier on transceiver %s"
  130. " failed\n", __func__,
  131. dev_name(otgwl_xceiv->dev));
  132. otgwl_xceiv = NULL;
  133. wake_lock_destroy(&vbus_lock.wakelock);
  134. return ret;
  135. }
  136. otgwl_handle_event(otgwl_xceiv->last_event);
  137. return ret;
  138. }
  139. late_initcall(otg_wakelock_init);