panel-osd-osd101t2587-53ts.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
  4. * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  5. */
  6. #include <linux/module.h>
  7. #include <linux/of.h>
  8. #include <linux/regulator/consumer.h>
  9. #include <drm/drm_crtc.h>
  10. #include <drm/drm_device.h>
  11. #include <drm/drm_mipi_dsi.h>
  12. #include <drm/drm_panel.h>
  13. #include <video/mipi_display.h>
  14. struct osd101t2587_panel {
  15. struct drm_panel base;
  16. struct mipi_dsi_device *dsi;
  17. struct regulator *supply;
  18. bool prepared;
  19. bool enabled;
  20. const struct drm_display_mode *default_mode;
  21. };
  22. static inline struct osd101t2587_panel *ti_osd_panel(struct drm_panel *panel)
  23. {
  24. return container_of(panel, struct osd101t2587_panel, base);
  25. }
  26. static int osd101t2587_panel_disable(struct drm_panel *panel)
  27. {
  28. struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
  29. int ret;
  30. if (!osd101t2587->enabled)
  31. return 0;
  32. ret = mipi_dsi_shutdown_peripheral(osd101t2587->dsi);
  33. osd101t2587->enabled = false;
  34. return ret;
  35. }
  36. static int osd101t2587_panel_unprepare(struct drm_panel *panel)
  37. {
  38. struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
  39. if (!osd101t2587->prepared)
  40. return 0;
  41. regulator_disable(osd101t2587->supply);
  42. osd101t2587->prepared = false;
  43. return 0;
  44. }
  45. static int osd101t2587_panel_prepare(struct drm_panel *panel)
  46. {
  47. struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
  48. int ret;
  49. if (osd101t2587->prepared)
  50. return 0;
  51. ret = regulator_enable(osd101t2587->supply);
  52. if (!ret)
  53. osd101t2587->prepared = true;
  54. return ret;
  55. }
  56. static int osd101t2587_panel_enable(struct drm_panel *panel)
  57. {
  58. struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
  59. int ret;
  60. if (osd101t2587->enabled)
  61. return 0;
  62. ret = mipi_dsi_turn_on_peripheral(osd101t2587->dsi);
  63. if (ret)
  64. return ret;
  65. osd101t2587->enabled = true;
  66. return ret;
  67. }
  68. static const struct drm_display_mode default_mode_osd101t2587 = {
  69. .clock = 164400,
  70. .hdisplay = 1920,
  71. .hsync_start = 1920 + 152,
  72. .hsync_end = 1920 + 152 + 52,
  73. .htotal = 1920 + 152 + 52 + 20,
  74. .vdisplay = 1200,
  75. .vsync_start = 1200 + 24,
  76. .vsync_end = 1200 + 24 + 6,
  77. .vtotal = 1200 + 24 + 6 + 48,
  78. .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
  79. };
  80. static int osd101t2587_panel_get_modes(struct drm_panel *panel,
  81. struct drm_connector *connector)
  82. {
  83. struct osd101t2587_panel *osd101t2587 = ti_osd_panel(panel);
  84. struct drm_display_mode *mode;
  85. mode = drm_mode_duplicate(connector->dev, osd101t2587->default_mode);
  86. if (!mode) {
  87. dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",
  88. osd101t2587->default_mode->hdisplay,
  89. osd101t2587->default_mode->vdisplay,
  90. drm_mode_vrefresh(osd101t2587->default_mode));
  91. return -ENOMEM;
  92. }
  93. drm_mode_set_name(mode);
  94. drm_mode_probed_add(connector, mode);
  95. connector->display_info.width_mm = 217;
  96. connector->display_info.height_mm = 136;
  97. return 1;
  98. }
  99. static const struct drm_panel_funcs osd101t2587_panel_funcs = {
  100. .disable = osd101t2587_panel_disable,
  101. .unprepare = osd101t2587_panel_unprepare,
  102. .prepare = osd101t2587_panel_prepare,
  103. .enable = osd101t2587_panel_enable,
  104. .get_modes = osd101t2587_panel_get_modes,
  105. };
  106. static const struct of_device_id osd101t2587_of_match[] = {
  107. {
  108. .compatible = "osddisplays,osd101t2587-53ts",
  109. .data = &default_mode_osd101t2587,
  110. }, {
  111. /* sentinel */
  112. }
  113. };
  114. MODULE_DEVICE_TABLE(of, osd101t2587_of_match);
  115. static int osd101t2587_panel_add(struct osd101t2587_panel *osd101t2587)
  116. {
  117. struct device *dev = &osd101t2587->dsi->dev;
  118. int ret;
  119. osd101t2587->supply = devm_regulator_get(dev, "power");
  120. if (IS_ERR(osd101t2587->supply))
  121. return PTR_ERR(osd101t2587->supply);
  122. drm_panel_init(&osd101t2587->base, &osd101t2587->dsi->dev,
  123. &osd101t2587_panel_funcs, DRM_MODE_CONNECTOR_DSI);
  124. ret = drm_panel_of_backlight(&osd101t2587->base);
  125. if (ret)
  126. return ret;
  127. drm_panel_add(&osd101t2587->base);
  128. return 0;
  129. }
  130. static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi)
  131. {
  132. struct osd101t2587_panel *osd101t2587;
  133. const struct of_device_id *id;
  134. int ret;
  135. id = of_match_node(osd101t2587_of_match, dsi->dev.of_node);
  136. if (!id)
  137. return -ENODEV;
  138. dsi->lanes = 4;
  139. dsi->format = MIPI_DSI_FMT_RGB888;
  140. dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
  141. MIPI_DSI_MODE_VIDEO_BURST |
  142. MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
  143. MIPI_DSI_MODE_EOT_PACKET;
  144. osd101t2587 = devm_kzalloc(&dsi->dev, sizeof(*osd101t2587), GFP_KERNEL);
  145. if (!osd101t2587)
  146. return -ENOMEM;
  147. mipi_dsi_set_drvdata(dsi, osd101t2587);
  148. osd101t2587->dsi = dsi;
  149. osd101t2587->default_mode = id->data;
  150. ret = osd101t2587_panel_add(osd101t2587);
  151. if (ret < 0)
  152. return ret;
  153. ret = mipi_dsi_attach(dsi);
  154. if (ret)
  155. drm_panel_remove(&osd101t2587->base);
  156. return ret;
  157. }
  158. static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi)
  159. {
  160. struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi);
  161. int ret;
  162. ret = drm_panel_disable(&osd101t2587->base);
  163. if (ret < 0)
  164. dev_warn(&dsi->dev, "failed to disable panel: %d\n", ret);
  165. drm_panel_unprepare(&osd101t2587->base);
  166. drm_panel_remove(&osd101t2587->base);
  167. ret = mipi_dsi_detach(dsi);
  168. if (ret < 0)
  169. dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
  170. return ret;
  171. }
  172. static void osd101t2587_panel_shutdown(struct mipi_dsi_device *dsi)
  173. {
  174. struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi);
  175. drm_panel_disable(&osd101t2587->base);
  176. drm_panel_unprepare(&osd101t2587->base);
  177. }
  178. static struct mipi_dsi_driver osd101t2587_panel_driver = {
  179. .driver = {
  180. .name = "panel-osd-osd101t2587-53ts",
  181. .of_match_table = osd101t2587_of_match,
  182. },
  183. .probe = osd101t2587_panel_probe,
  184. .remove = osd101t2587_panel_remove,
  185. .shutdown = osd101t2587_panel_shutdown,
  186. };
  187. module_mipi_dsi_driver(osd101t2587_panel_driver);
  188. MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
  189. MODULE_DESCRIPTION("OSD101T2587-53TS DSI panel");
  190. MODULE_LICENSE("GPL v2");