dw_hdmi-light.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/component.h>
  3. #include <linux/device.h>
  4. #include <linux/module.h>
  5. #include <linux/platform_device.h>
  6. #include <linux/pm_runtime.h>
  7. #include <linux/regmap.h>
  8. #include <drm/drm_atomic_helper.h>
  9. #include <drm/drm_encoder.h>
  10. #include <drm/drm_of.h>
  11. #include <drm/drm_simple_kms_helper.h>
  12. #include <drm/bridge/dw_hdmi.h>
  13. #include "dw_hdmi_tx_phy_gen2.h"
  14. struct light_hdmi {
  15. struct device *dev;
  16. struct drm_encoder encoder;
  17. struct dw_hdmi *dw_hdmi;
  18. /* TODO: may not be used */
  19. struct regmap *sysreg;
  20. };
  21. static void dw_hdmi_light_encoder_enable(struct drm_encoder *encoder)
  22. {
  23. }
  24. static int dw_hdmi_light_encoder_atomic_check(struct drm_encoder *encoder,
  25. struct drm_crtc_state *crtc_state,
  26. struct drm_connector_state *conn_state)
  27. {
  28. return 0;
  29. }
  30. static struct dw_hdmi_plat_data light_hdmi_drv_data = {
  31. .mode_valid = dw_hdmi_tx_phy_gen2_mode_valid,
  32. .configure_phy = dw_hdmi_tx_phy_gen2_configure,
  33. };
  34. static const struct of_device_id dw_hdmi_light_dt_ids[] = {
  35. {
  36. .compatible = "thead,light-hdmi-tx",
  37. .data = &light_hdmi_drv_data,
  38. },
  39. {
  40. /* sentinel */
  41. },
  42. };
  43. static const struct drm_encoder_helper_funcs dw_hdmi_light_encoder_helper_funcs = {
  44. .enable = dw_hdmi_light_encoder_enable,
  45. .atomic_check = dw_hdmi_light_encoder_atomic_check,
  46. };
  47. static int dw_hdmi_light_bind(struct device *dev, struct device *master,
  48. void *data)
  49. {
  50. int ret = 0;
  51. struct platform_device *pdev = to_platform_device(dev);
  52. struct device_node *np = dev->of_node;
  53. const struct of_device_id *match;
  54. const struct dw_hdmi_plat_data *plat_data;
  55. struct light_hdmi *hdmi;
  56. struct drm_device *drm = data;
  57. struct drm_encoder *encoder;
  58. if (!np)
  59. return -ENODEV;
  60. hdmi = dev_get_drvdata(dev);
  61. match = of_match_node(dw_hdmi_light_dt_ids, np);
  62. if (unlikely(!match))
  63. return -ENODEV;
  64. plat_data = match->data;
  65. hdmi->dev = &pdev->dev;
  66. encoder = &hdmi->encoder;
  67. encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, np);
  68. if (!encoder->possible_crtcs)
  69. return -EPROBE_DEFER;
  70. drm_encoder_helper_add(encoder, &dw_hdmi_light_encoder_helper_funcs);
  71. drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
  72. hdmi->dw_hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
  73. if (IS_ERR(hdmi->dw_hdmi)) {
  74. ret = PTR_ERR(hdmi->dw_hdmi);
  75. drm_encoder_cleanup(encoder);
  76. }
  77. pm_runtime_enable(dev);
  78. return ret;
  79. }
  80. static void dw_hdmi_light_unbind(struct device *dev, struct device *master,
  81. void *data)
  82. {
  83. struct light_hdmi *hdmi = dev_get_drvdata(dev);
  84. pm_runtime_disable(dev);
  85. dw_hdmi_unbind(hdmi->dw_hdmi);
  86. }
  87. static const struct component_ops dw_hdmi_light_ops = {
  88. .bind = dw_hdmi_light_bind,
  89. .unbind = dw_hdmi_light_unbind,
  90. };
  91. static int dw_hdmi_light_probe(struct platform_device *pdev)
  92. {
  93. struct light_hdmi *hdmi;
  94. hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
  95. if (!hdmi)
  96. return -ENOMEM;
  97. platform_set_drvdata(pdev, hdmi);
  98. return component_add(&pdev->dev, &dw_hdmi_light_ops);
  99. }
  100. static int dw_hdmi_light_remove(struct platform_device *pdev)
  101. {
  102. component_del(&pdev->dev, &dw_hdmi_light_ops);
  103. return 0;
  104. }
  105. #ifdef CONFIG_PM
  106. static int hdmi_runtime_suspend(struct device *dev)
  107. {
  108. struct light_hdmi *hdmi = dev_get_drvdata(dev);
  109. return dw_hdmi_runtime_suspend(hdmi->dw_hdmi);
  110. }
  111. static int hdmi_runtime_resume(struct device *dev)
  112. {
  113. struct light_hdmi *hdmi = dev_get_drvdata(dev);
  114. return dw_hdmi_runtime_resume(hdmi->dw_hdmi);
  115. }
  116. #endif
  117. static const struct dev_pm_ops dw_hdmi_pm_ops = {
  118. SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
  119. pm_runtime_force_resume)
  120. SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
  121. };
  122. struct platform_driver dw_hdmi_light_platform_driver = {
  123. .probe = dw_hdmi_light_probe,
  124. .remove = dw_hdmi_light_remove,
  125. .driver = {
  126. .name = "dwhdmi-light",
  127. .of_match_table = dw_hdmi_light_dt_ids,
  128. .pm = &dw_hdmi_pm_ops,
  129. },
  130. };
  131. MODULE_AUTHOR("You Xiao <youxiao.fc@linux.alibaba.com>");
  132. MODULE_DESCRIPTION("Light Platforms Specific DW-HDMI Driver Extention");
  133. MODULE_LICENSE("GPL v2");
  134. MODULE_ALIAS("platform:dwhdmi-light");