dp_bridge_hpd.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
  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 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. */
  14. #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
  15. #include <linux/interrupt.h>
  16. #include <linux/delay.h>
  17. #include <linux/kernel.h>
  18. #include <linux/kthread.h>
  19. #include <linux/slab.h>
  20. #include <linux/device.h>
  21. #include "dp_bridge_hpd.h"
  22. struct dp_bridge_hpd_private {
  23. struct device *dev;
  24. struct dp_hpd base;
  25. struct dp_aux_bridge *bridge;
  26. struct delayed_work work;
  27. struct dp_hpd_cb *cb;
  28. bool hpd;
  29. bool hpd_irq;
  30. struct mutex hpd_lock;
  31. };
  32. static int dp_bridge_hpd_connect(struct dp_bridge_hpd_private *bridge_hpd,
  33. bool hpd)
  34. {
  35. int rc = 0;
  36. if (!bridge_hpd) {
  37. pr_err("invalid input\n");
  38. rc = -EINVAL;
  39. goto error;
  40. }
  41. bridge_hpd->base.hpd_high = hpd;
  42. bridge_hpd->base.alt_mode_cfg_done = hpd;
  43. bridge_hpd->base.hpd_irq = false;
  44. if (!bridge_hpd->cb ||
  45. !bridge_hpd->cb->configure ||
  46. !bridge_hpd->cb->disconnect) {
  47. pr_err("invalid cb\n");
  48. rc = -EINVAL;
  49. goto error;
  50. }
  51. if (hpd)
  52. rc = bridge_hpd->cb->configure(bridge_hpd->dev);
  53. else
  54. rc = bridge_hpd->cb->disconnect(bridge_hpd->dev);
  55. error:
  56. return rc;
  57. }
  58. static int dp_bridge_hpd_attention(struct dp_bridge_hpd_private *bridge_hpd)
  59. {
  60. int rc = 0;
  61. if (!bridge_hpd) {
  62. pr_err("invalid input\n");
  63. rc = -EINVAL;
  64. goto error;
  65. }
  66. bridge_hpd->base.hpd_irq = true;
  67. if (bridge_hpd->cb && bridge_hpd->cb->attention)
  68. rc = bridge_hpd->cb->attention(bridge_hpd->dev);
  69. error:
  70. return rc;
  71. }
  72. static void dp_bridge_hpd_work(struct work_struct *work)
  73. {
  74. struct delayed_work *dw = to_delayed_work(work);
  75. struct dp_bridge_hpd_private *bridge_hpd = container_of(dw,
  76. struct dp_bridge_hpd_private, work);
  77. mutex_lock(&bridge_hpd->hpd_lock);
  78. if (bridge_hpd->hpd_irq)
  79. dp_bridge_hpd_attention(bridge_hpd);
  80. else
  81. dp_bridge_hpd_connect(bridge_hpd, bridge_hpd->hpd);
  82. mutex_unlock(&bridge_hpd->hpd_lock);
  83. }
  84. static int dp_bridge_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
  85. {
  86. int rc = 0;
  87. struct dp_bridge_hpd_private *bridge_hpd;
  88. if (!dp_hpd) {
  89. pr_err("invalid input\n");
  90. rc = -EINVAL;
  91. goto error;
  92. }
  93. bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
  94. dp_bridge_hpd_connect(bridge_hpd, hpd);
  95. error:
  96. return rc;
  97. }
  98. static int dp_bridge_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
  99. {
  100. int rc = 0;
  101. struct dp_bridge_hpd_private *bridge_hpd;
  102. if (!dp_hpd) {
  103. pr_err("invalid input\n");
  104. rc = -EINVAL;
  105. goto error;
  106. }
  107. bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
  108. dp_bridge_hpd_attention(bridge_hpd);
  109. error:
  110. return rc;
  111. }
  112. static int dp_bridge_hpd_cb(void *dp_hpd, bool hpd, bool hpd_irq)
  113. {
  114. struct dp_bridge_hpd_private *bridge_hpd = dp_hpd;
  115. mutex_lock(&bridge_hpd->hpd_lock);
  116. bridge_hpd->hpd = hpd;
  117. bridge_hpd->hpd_irq = hpd_irq;
  118. queue_delayed_work(system_wq, &bridge_hpd->work, 0);
  119. mutex_unlock(&bridge_hpd->hpd_lock);
  120. return 0;
  121. }
  122. static int dp_bridge_hpd_register(struct dp_hpd *dp_hpd)
  123. {
  124. struct dp_bridge_hpd_private *bridge_hpd;
  125. if (!dp_hpd)
  126. return -EINVAL;
  127. bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
  128. return bridge_hpd->bridge->register_hpd(bridge_hpd->bridge,
  129. dp_bridge_hpd_cb, bridge_hpd);
  130. }
  131. struct dp_hpd *dp_bridge_hpd_get(struct device *dev,
  132. struct dp_hpd_cb *cb, struct dp_aux_bridge *aux_bridge)
  133. {
  134. int rc = 0;
  135. struct dp_bridge_hpd_private *bridge_hpd;
  136. if (!dev || !cb) {
  137. pr_err("invalid device\n");
  138. rc = -EINVAL;
  139. goto error;
  140. }
  141. bridge_hpd = devm_kzalloc(dev, sizeof(*bridge_hpd), GFP_KERNEL);
  142. if (!bridge_hpd) {
  143. rc = -ENOMEM;
  144. goto error;
  145. }
  146. bridge_hpd->dev = dev;
  147. bridge_hpd->cb = cb;
  148. bridge_hpd->bridge = aux_bridge;
  149. mutex_init(&bridge_hpd->hpd_lock);
  150. INIT_DELAYED_WORK(&bridge_hpd->work, dp_bridge_hpd_work);
  151. bridge_hpd->base.simulate_connect = dp_bridge_hpd_simulate_connect;
  152. bridge_hpd->base.simulate_attention = dp_bridge_hpd_simulate_attention;
  153. bridge_hpd->base.register_hpd = dp_bridge_hpd_register;
  154. return &bridge_hpd->base;
  155. error:
  156. return ERR_PTR(rc);
  157. }
  158. void dp_bridge_hpd_put(struct dp_hpd *dp_hpd)
  159. {
  160. struct dp_bridge_hpd_private *bridge_hpd;
  161. if (!dp_hpd)
  162. return;
  163. bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
  164. devm_kfree(bridge_hpd->dev, bridge_hpd);
  165. }