otg-wakelock.c 3.6 KB

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