ti-tpd12s015.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * TPD12S015 HDMI ESD protection & level shifter chip driver
  4. *
  5. * Copyright (C) 2019 Texas Instruments Incorporated
  6. *
  7. * Based on the omapdrm-specific encoder-opa362 driver
  8. *
  9. * Copyright (C) 2013 Texas Instruments Incorporated
  10. * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
  11. */
  12. #include <linux/delay.h>
  13. #include <linux/gpio/consumer.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/module.h>
  16. #include <linux/mutex.h>
  17. #include <linux/of.h>
  18. #include <linux/of_graph.h>
  19. #include <linux/platform_device.h>
  20. #include <drm/drm_bridge.h>
  21. struct tpd12s015_device {
  22. struct drm_bridge bridge;
  23. struct gpio_desc *ct_cp_hpd_gpio;
  24. struct gpio_desc *ls_oe_gpio;
  25. struct gpio_desc *hpd_gpio;
  26. int hpd_irq;
  27. struct drm_bridge *next_bridge;
  28. };
  29. static inline struct tpd12s015_device *to_tpd12s015(struct drm_bridge *bridge)
  30. {
  31. return container_of(bridge, struct tpd12s015_device, bridge);
  32. }
  33. static int tpd12s015_attach(struct drm_bridge *bridge,
  34. enum drm_bridge_attach_flags flags)
  35. {
  36. struct tpd12s015_device *tpd = to_tpd12s015(bridge);
  37. int ret;
  38. if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
  39. return -EINVAL;
  40. ret = drm_bridge_attach(bridge->encoder, tpd->next_bridge,
  41. bridge, flags);
  42. if (ret < 0)
  43. return ret;
  44. gpiod_set_value_cansleep(tpd->ls_oe_gpio, 1);
  45. /* DC-DC converter needs at max 300us to get to 90% of 5V. */
  46. usleep_range(300, 1000);
  47. return 0;
  48. }
  49. static void tpd12s015_detach(struct drm_bridge *bridge)
  50. {
  51. struct tpd12s015_device *tpd = to_tpd12s015(bridge);
  52. gpiod_set_value_cansleep(tpd->ls_oe_gpio, 0);
  53. }
  54. static enum drm_connector_status tpd12s015_detect(struct drm_bridge *bridge)
  55. {
  56. struct tpd12s015_device *tpd = to_tpd12s015(bridge);
  57. if (gpiod_get_value_cansleep(tpd->hpd_gpio))
  58. return connector_status_connected;
  59. else
  60. return connector_status_disconnected;
  61. }
  62. static void tpd12s015_hpd_enable(struct drm_bridge *bridge)
  63. {
  64. struct tpd12s015_device *tpd = to_tpd12s015(bridge);
  65. gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 1);
  66. }
  67. static void tpd12s015_hpd_disable(struct drm_bridge *bridge)
  68. {
  69. struct tpd12s015_device *tpd = to_tpd12s015(bridge);
  70. gpiod_set_value_cansleep(tpd->ct_cp_hpd_gpio, 0);
  71. }
  72. static const struct drm_bridge_funcs tpd12s015_bridge_funcs = {
  73. .attach = tpd12s015_attach,
  74. .detach = tpd12s015_detach,
  75. .detect = tpd12s015_detect,
  76. .hpd_enable = tpd12s015_hpd_enable,
  77. .hpd_disable = tpd12s015_hpd_disable,
  78. };
  79. static irqreturn_t tpd12s015_hpd_isr(int irq, void *data)
  80. {
  81. struct tpd12s015_device *tpd = data;
  82. struct drm_bridge *bridge = &tpd->bridge;
  83. drm_bridge_hpd_notify(bridge, tpd12s015_detect(bridge));
  84. return IRQ_HANDLED;
  85. }
  86. static int tpd12s015_probe(struct platform_device *pdev)
  87. {
  88. struct tpd12s015_device *tpd;
  89. struct device_node *node;
  90. struct gpio_desc *gpio;
  91. int ret;
  92. tpd = devm_kzalloc(&pdev->dev, sizeof(*tpd), GFP_KERNEL);
  93. if (!tpd)
  94. return -ENOMEM;
  95. platform_set_drvdata(pdev, tpd);
  96. tpd->bridge.funcs = &tpd12s015_bridge_funcs;
  97. tpd->bridge.of_node = pdev->dev.of_node;
  98. tpd->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
  99. tpd->bridge.ops = DRM_BRIDGE_OP_DETECT;
  100. /* Get the next bridge, connected to port@1. */
  101. node = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);
  102. if (!node)
  103. return -ENODEV;
  104. tpd->next_bridge = of_drm_find_bridge(node);
  105. of_node_put(node);
  106. if (!tpd->next_bridge)
  107. return -EPROBE_DEFER;
  108. /* Get the control and HPD GPIOs. */
  109. gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
  110. GPIOD_OUT_LOW);
  111. if (IS_ERR(gpio))
  112. return PTR_ERR(gpio);
  113. tpd->ct_cp_hpd_gpio = gpio;
  114. gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
  115. GPIOD_OUT_LOW);
  116. if (IS_ERR(gpio))
  117. return PTR_ERR(gpio);
  118. tpd->ls_oe_gpio = gpio;
  119. gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN);
  120. if (IS_ERR(gpio))
  121. return PTR_ERR(gpio);
  122. tpd->hpd_gpio = gpio;
  123. /* Register the IRQ if the HPD GPIO is IRQ-capable. */
  124. tpd->hpd_irq = gpiod_to_irq(tpd->hpd_gpio);
  125. if (tpd->hpd_irq >= 0) {
  126. ret = devm_request_threaded_irq(&pdev->dev, tpd->hpd_irq, NULL,
  127. tpd12s015_hpd_isr,
  128. IRQF_TRIGGER_RISING |
  129. IRQF_TRIGGER_FALLING |
  130. IRQF_ONESHOT,
  131. "tpd12s015 hpd", tpd);
  132. if (ret)
  133. return ret;
  134. tpd->bridge.ops |= DRM_BRIDGE_OP_HPD;
  135. }
  136. /* Register the DRM bridge. */
  137. drm_bridge_add(&tpd->bridge);
  138. return 0;
  139. }
  140. static int __exit tpd12s015_remove(struct platform_device *pdev)
  141. {
  142. struct tpd12s015_device *tpd = platform_get_drvdata(pdev);
  143. drm_bridge_remove(&tpd->bridge);
  144. return 0;
  145. }
  146. static const struct of_device_id tpd12s015_of_match[] = {
  147. { .compatible = "ti,tpd12s015", },
  148. {},
  149. };
  150. MODULE_DEVICE_TABLE(of, tpd12s015_of_match);
  151. static struct platform_driver tpd12s015_driver = {
  152. .probe = tpd12s015_probe,
  153. .remove = __exit_p(tpd12s015_remove),
  154. .driver = {
  155. .name = "tpd12s015",
  156. .of_match_table = tpd12s015_of_match,
  157. },
  158. };
  159. module_platform_driver(tpd12s015_driver);
  160. MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
  161. MODULE_DESCRIPTION("TPD12S015 HDMI level shifter and ESD protection driver");
  162. MODULE_LICENSE("GPL");