otg-wakelock.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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/module.h>
  19. #include <linux/notifier.h>
  20. #include <linux/wakelock.h>
  21. #include <linux/spinlock.h>
  22. #include <linux/usb/otg.h>
  23. #define TEMPORARY_HOLD_TIME 2000
  24. static bool enabled = true;
  25. static struct usb_phy *otgwl_xceiv;
  26. static struct notifier_block otgwl_nb;
  27. /*
  28. * otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the
  29. * held field is updated to match.
  30. */
  31. static DEFINE_SPINLOCK(otgwl_spinlock);
  32. /*
  33. * Only one lock, but since these 3 fields are associated with each other...
  34. */
  35. struct otgwl_lock {
  36. char name[40];
  37. struct wake_lock wakelock;
  38. bool held;
  39. };
  40. /*
  41. * VBUS present lock. Also used as a timed lock on charger
  42. * connect/disconnect and USB host disconnect, to allow the system
  43. * to react to the change in power.
  44. */
  45. static struct otgwl_lock vbus_lock;
  46. static void otgwl_hold(struct otgwl_lock *lock)
  47. {
  48. if (!lock->held) {
  49. wake_lock(&lock->wakelock);
  50. lock->held = true;
  51. }
  52. }
  53. static void otgwl_temporary_hold(struct otgwl_lock *lock)
  54. {
  55. wake_lock_timeout(&lock->wakelock,
  56. msecs_to_jiffies(TEMPORARY_HOLD_TIME));
  57. lock->held = false;
  58. }
  59. static void otgwl_drop(struct otgwl_lock *lock)
  60. {
  61. if (lock->held) {
  62. wake_unlock(&lock->wakelock);
  63. lock->held = false;
  64. }
  65. }
  66. static void otgwl_handle_event(unsigned long event)
  67. {
  68. unsigned long irqflags;
  69. spin_lock_irqsave(&otgwl_spinlock, irqflags);
  70. if (!enabled) {
  71. otgwl_drop(&vbus_lock);
  72. spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
  73. return;
  74. }
  75. switch (event) {
  76. case USB_EVENT_VBUS:
  77. case USB_EVENT_ENUMERATED:
  78. otgwl_hold(&vbus_lock);
  79. break;
  80. case USB_EVENT_NONE:
  81. case USB_EVENT_ID:
  82. case USB_EVENT_CHARGER:
  83. otgwl_temporary_hold(&vbus_lock);
  84. break;
  85. default:
  86. break;
  87. }
  88. spin_unlock_irqrestore(&otgwl_spinlock, irqflags);
  89. }
  90. static int otgwl_otg_notifications(struct notifier_block *nb,
  91. unsigned long event, void *unused)
  92. {
  93. otgwl_handle_event(event);
  94. return NOTIFY_OK;
  95. }
  96. static int set_enabled(const char *val, const struct kernel_param *kp)
  97. {
  98. int rv = param_set_bool(val, kp);
  99. if (rv)
  100. return rv;
  101. if (otgwl_xceiv)
  102. otgwl_handle_event(otgwl_xceiv->last_event);
  103. return 0;
  104. }
  105. static struct kernel_param_ops enabled_param_ops = {
  106. .set = set_enabled,
  107. .get = param_get_bool,
  108. };
  109. module_param_cb(enabled, &enabled_param_ops, &enabled, 0644);
  110. MODULE_PARM_DESC(enabled, "enable wakelock when VBUS present");
  111. static int __init otg_wakelock_init(void)
  112. {
  113. int ret;
  114. otgwl_xceiv = usb_get_transceiver();
  115. if (!otgwl_xceiv) {
  116. pr_err("%s: No USB transceiver found\n", __func__);
  117. return -ENODEV;
  118. }
  119. snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s",
  120. dev_name(otgwl_xceiv->dev));
  121. wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND,
  122. vbus_lock.name);
  123. otgwl_nb.notifier_call = otgwl_otg_notifications;
  124. ret = usb_register_notifier(otgwl_xceiv, &otgwl_nb);
  125. if (ret) {
  126. pr_err("%s: usb_register_notifier on transceiver %s"
  127. " failed\n", __func__,
  128. dev_name(otgwl_xceiv->dev));
  129. otgwl_xceiv = NULL;
  130. wake_lock_destroy(&vbus_lock.wakelock);
  131. return ret;
  132. }
  133. otgwl_handle_event(otgwl_xceiv->last_event);
  134. return ret;
  135. }
  136. late_initcall(otg_wakelock_init);