encoder-tpd12s015.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * TPD12S015 HDMI ESD protection & level shifter chip driver
  3. *
  4. * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
  5. * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published by
  9. * the Free Software Foundation.
  10. */
  11. #include <linux/completion.h>
  12. #include <linux/delay.h>
  13. #include <linux/module.h>
  14. #include <linux/slab.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/gpio/consumer.h>
  17. #include <linux/mutex.h>
  18. #include "../dss/omapdss.h"
  19. struct panel_drv_data {
  20. struct omap_dss_device dssdev;
  21. void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
  22. void *hpd_cb_data;
  23. struct mutex hpd_lock;
  24. struct gpio_desc *ct_cp_hpd_gpio;
  25. struct gpio_desc *ls_oe_gpio;
  26. struct gpio_desc *hpd_gpio;
  27. };
  28. #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
  29. static int tpd_connect(struct omap_dss_device *src,
  30. struct omap_dss_device *dst)
  31. {
  32. struct panel_drv_data *ddata = to_panel_data(dst);
  33. int r;
  34. r = omapdss_device_connect(dst->dss, dst, dst->next);
  35. if (r)
  36. return r;
  37. gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
  38. gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
  39. /* DC-DC converter needs at max 300us to get to 90% of 5V */
  40. udelay(300);
  41. return 0;
  42. }
  43. static void tpd_disconnect(struct omap_dss_device *src,
  44. struct omap_dss_device *dst)
  45. {
  46. struct panel_drv_data *ddata = to_panel_data(dst);
  47. gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
  48. gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
  49. omapdss_device_disconnect(dst, dst->next);
  50. }
  51. static int tpd_enable(struct omap_dss_device *dssdev)
  52. {
  53. struct omap_dss_device *src = dssdev->src;
  54. int r;
  55. if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
  56. return 0;
  57. r = src->ops->enable(src);
  58. if (r)
  59. return r;
  60. dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
  61. return r;
  62. }
  63. static void tpd_disable(struct omap_dss_device *dssdev)
  64. {
  65. struct omap_dss_device *src = dssdev->src;
  66. if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
  67. return;
  68. src->ops->disable(src);
  69. dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
  70. }
  71. static bool tpd_detect(struct omap_dss_device *dssdev)
  72. {
  73. struct panel_drv_data *ddata = to_panel_data(dssdev);
  74. return gpiod_get_value_cansleep(ddata->hpd_gpio);
  75. }
  76. static void tpd_register_hpd_cb(struct omap_dss_device *dssdev,
  77. void (*cb)(void *cb_data,
  78. enum drm_connector_status status),
  79. void *cb_data)
  80. {
  81. struct panel_drv_data *ddata = to_panel_data(dssdev);
  82. mutex_lock(&ddata->hpd_lock);
  83. ddata->hpd_cb = cb;
  84. ddata->hpd_cb_data = cb_data;
  85. mutex_unlock(&ddata->hpd_lock);
  86. }
  87. static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
  88. {
  89. struct panel_drv_data *ddata = to_panel_data(dssdev);
  90. mutex_lock(&ddata->hpd_lock);
  91. ddata->hpd_cb = NULL;
  92. ddata->hpd_cb_data = NULL;
  93. mutex_unlock(&ddata->hpd_lock);
  94. }
  95. static const struct omap_dss_device_ops tpd_ops = {
  96. .connect = tpd_connect,
  97. .disconnect = tpd_disconnect,
  98. .enable = tpd_enable,
  99. .disable = tpd_disable,
  100. .detect = tpd_detect,
  101. .register_hpd_cb = tpd_register_hpd_cb,
  102. .unregister_hpd_cb = tpd_unregister_hpd_cb,
  103. };
  104. static irqreturn_t tpd_hpd_isr(int irq, void *data)
  105. {
  106. struct panel_drv_data *ddata = data;
  107. mutex_lock(&ddata->hpd_lock);
  108. if (ddata->hpd_cb) {
  109. enum drm_connector_status status;
  110. if (tpd_detect(&ddata->dssdev))
  111. status = connector_status_connected;
  112. else
  113. status = connector_status_disconnected;
  114. ddata->hpd_cb(ddata->hpd_cb_data, status);
  115. }
  116. mutex_unlock(&ddata->hpd_lock);
  117. return IRQ_HANDLED;
  118. }
  119. static int tpd_probe(struct platform_device *pdev)
  120. {
  121. struct omap_dss_device *dssdev;
  122. struct panel_drv_data *ddata;
  123. int r;
  124. struct gpio_desc *gpio;
  125. ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
  126. if (!ddata)
  127. return -ENOMEM;
  128. platform_set_drvdata(pdev, ddata);
  129. gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
  130. GPIOD_OUT_LOW);
  131. if (IS_ERR(gpio))
  132. return PTR_ERR(gpio);
  133. ddata->ct_cp_hpd_gpio = gpio;
  134. gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
  135. GPIOD_OUT_LOW);
  136. if (IS_ERR(gpio))
  137. return PTR_ERR(gpio);
  138. ddata->ls_oe_gpio = gpio;
  139. gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
  140. GPIOD_IN);
  141. if (IS_ERR(gpio))
  142. return PTR_ERR(gpio);
  143. ddata->hpd_gpio = gpio;
  144. mutex_init(&ddata->hpd_lock);
  145. r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio),
  146. NULL, tpd_hpd_isr,
  147. IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
  148. "tpd12s015 hpd", ddata);
  149. if (r)
  150. return r;
  151. dssdev = &ddata->dssdev;
  152. dssdev->ops = &tpd_ops;
  153. dssdev->dev = &pdev->dev;
  154. dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
  155. dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
  156. dssdev->owner = THIS_MODULE;
  157. dssdev->of_ports = BIT(1) | BIT(0);
  158. dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT
  159. | OMAP_DSS_DEVICE_OP_HPD;
  160. dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
  161. if (IS_ERR(dssdev->next)) {
  162. if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
  163. dev_err(&pdev->dev, "failed to find video sink\n");
  164. return PTR_ERR(dssdev->next);
  165. }
  166. omapdss_device_register(dssdev);
  167. return 0;
  168. }
  169. static int __exit tpd_remove(struct platform_device *pdev)
  170. {
  171. struct panel_drv_data *ddata = platform_get_drvdata(pdev);
  172. struct omap_dss_device *dssdev = &ddata->dssdev;
  173. if (dssdev->next)
  174. omapdss_device_put(dssdev->next);
  175. omapdss_device_unregister(&ddata->dssdev);
  176. WARN_ON(omapdss_device_is_enabled(dssdev));
  177. if (omapdss_device_is_enabled(dssdev))
  178. tpd_disable(dssdev);
  179. WARN_ON(omapdss_device_is_connected(dssdev));
  180. if (omapdss_device_is_connected(dssdev))
  181. omapdss_device_disconnect(NULL, dssdev);
  182. return 0;
  183. }
  184. static const struct of_device_id tpd_of_match[] = {
  185. { .compatible = "omapdss,ti,tpd12s015", },
  186. {},
  187. };
  188. MODULE_DEVICE_TABLE(of, tpd_of_match);
  189. static struct platform_driver tpd_driver = {
  190. .probe = tpd_probe,
  191. .remove = __exit_p(tpd_remove),
  192. .driver = {
  193. .name = "tpd12s015",
  194. .of_match_table = tpd_of_match,
  195. .suppress_bind_attrs = true,
  196. },
  197. };
  198. module_platform_driver(tpd_driver);
  199. MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
  200. MODULE_DESCRIPTION("TPD12S015 driver");
  201. MODULE_LICENSE("GPL");