1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
4 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
7 #include <linux/module.h>
9 #include <linux/regulator/consumer.h>
11 #include <drm/drm_crtc.h>
12 #include <drm/drm_device.h>
13 #include <drm/drm_mipi_dsi.h>
14 #include <drm/drm_panel.h>
16 #include <video/mipi_display.h>
18 struct osd101t2587_panel
{
19 struct drm_panel base
;
20 struct mipi_dsi_device
*dsi
;
22 struct regulator
*supply
;
27 const struct drm_display_mode
*default_mode
;
30 static inline struct osd101t2587_panel
*ti_osd_panel(struct drm_panel
*panel
)
32 return container_of(panel
, struct osd101t2587_panel
, base
);
35 static int osd101t2587_panel_disable(struct drm_panel
*panel
)
37 struct osd101t2587_panel
*osd101t2587
= ti_osd_panel(panel
);
40 if (!osd101t2587
->enabled
)
43 ret
= mipi_dsi_shutdown_peripheral(osd101t2587
->dsi
);
45 osd101t2587
->enabled
= false;
50 static int osd101t2587_panel_unprepare(struct drm_panel
*panel
)
52 struct osd101t2587_panel
*osd101t2587
= ti_osd_panel(panel
);
54 if (!osd101t2587
->prepared
)
57 regulator_disable(osd101t2587
->supply
);
58 osd101t2587
->prepared
= false;
63 static int osd101t2587_panel_prepare(struct drm_panel
*panel
)
65 struct osd101t2587_panel
*osd101t2587
= ti_osd_panel(panel
);
68 if (osd101t2587
->prepared
)
71 ret
= regulator_enable(osd101t2587
->supply
);
73 osd101t2587
->prepared
= true;
78 static int osd101t2587_panel_enable(struct drm_panel
*panel
)
80 struct osd101t2587_panel
*osd101t2587
= ti_osd_panel(panel
);
83 if (osd101t2587
->enabled
)
86 ret
= mipi_dsi_turn_on_peripheral(osd101t2587
->dsi
);
90 osd101t2587
->enabled
= true;
95 static const struct drm_display_mode default_mode_osd101t2587
= {
98 .hsync_start
= 1920 + 152,
99 .hsync_end
= 1920 + 152 + 52,
100 .htotal
= 1920 + 152 + 52 + 20,
102 .vsync_start
= 1200 + 24,
103 .vsync_end
= 1200 + 24 + 6,
104 .vtotal
= 1200 + 24 + 6 + 48,
105 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
,
108 static int osd101t2587_panel_get_modes(struct drm_panel
*panel
,
109 struct drm_connector
*connector
)
111 struct osd101t2587_panel
*osd101t2587
= ti_osd_panel(panel
);
112 struct drm_display_mode
*mode
;
114 mode
= drm_mode_duplicate(connector
->dev
, osd101t2587
->default_mode
);
116 dev_err(panel
->dev
, "failed to add mode %ux%ux@%u\n",
117 osd101t2587
->default_mode
->hdisplay
,
118 osd101t2587
->default_mode
->vdisplay
,
119 drm_mode_vrefresh(osd101t2587
->default_mode
));
123 drm_mode_set_name(mode
);
125 drm_mode_probed_add(connector
, mode
);
127 connector
->display_info
.width_mm
= 217;
128 connector
->display_info
.height_mm
= 136;
133 static const struct drm_panel_funcs osd101t2587_panel_funcs
= {
134 .disable
= osd101t2587_panel_disable
,
135 .unprepare
= osd101t2587_panel_unprepare
,
136 .prepare
= osd101t2587_panel_prepare
,
137 .enable
= osd101t2587_panel_enable
,
138 .get_modes
= osd101t2587_panel_get_modes
,
141 static const struct of_device_id osd101t2587_of_match
[] = {
143 .compatible
= "osddisplays,osd101t2587-53ts",
144 .data
= &default_mode_osd101t2587
,
149 MODULE_DEVICE_TABLE(of
, osd101t2587_of_match
);
151 static int osd101t2587_panel_add(struct osd101t2587_panel
*osd101t2587
)
153 struct device
*dev
= &osd101t2587
->dsi
->dev
;
156 osd101t2587
->supply
= devm_regulator_get(dev
, "power");
157 if (IS_ERR(osd101t2587
->supply
))
158 return PTR_ERR(osd101t2587
->supply
);
160 drm_panel_init(&osd101t2587
->base
, &osd101t2587
->dsi
->dev
,
161 &osd101t2587_panel_funcs
, DRM_MODE_CONNECTOR_DSI
);
163 ret
= drm_panel_of_backlight(&osd101t2587
->base
);
167 drm_panel_add(&osd101t2587
->base
);
172 static int osd101t2587_panel_probe(struct mipi_dsi_device
*dsi
)
174 struct osd101t2587_panel
*osd101t2587
;
175 const struct of_device_id
*id
;
178 id
= of_match_node(osd101t2587_of_match
, dsi
->dev
.of_node
);
183 dsi
->format
= MIPI_DSI_FMT_RGB888
;
184 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
|
185 MIPI_DSI_MODE_VIDEO_BURST
|
186 MIPI_DSI_MODE_VIDEO_SYNC_PULSE
|
187 MIPI_DSI_MODE_EOT_PACKET
;
189 osd101t2587
= devm_kzalloc(&dsi
->dev
, sizeof(*osd101t2587
), GFP_KERNEL
);
193 mipi_dsi_set_drvdata(dsi
, osd101t2587
);
195 osd101t2587
->dsi
= dsi
;
196 osd101t2587
->default_mode
= id
->data
;
198 ret
= osd101t2587_panel_add(osd101t2587
);
202 ret
= mipi_dsi_attach(dsi
);
204 drm_panel_remove(&osd101t2587
->base
);
209 static int osd101t2587_panel_remove(struct mipi_dsi_device
*dsi
)
211 struct osd101t2587_panel
*osd101t2587
= mipi_dsi_get_drvdata(dsi
);
214 ret
= drm_panel_disable(&osd101t2587
->base
);
216 dev_warn(&dsi
->dev
, "failed to disable panel: %d\n", ret
);
218 drm_panel_unprepare(&osd101t2587
->base
);
219 drm_panel_remove(&osd101t2587
->base
);
221 ret
= mipi_dsi_detach(dsi
);
223 dev_err(&dsi
->dev
, "failed to detach from DSI host: %d\n", ret
);
228 static void osd101t2587_panel_shutdown(struct mipi_dsi_device
*dsi
)
230 struct osd101t2587_panel
*osd101t2587
= mipi_dsi_get_drvdata(dsi
);
232 drm_panel_disable(&osd101t2587
->base
);
233 drm_panel_unprepare(&osd101t2587
->base
);
236 static struct mipi_dsi_driver osd101t2587_panel_driver
= {
238 .name
= "panel-osd-osd101t2587-53ts",
239 .of_match_table
= osd101t2587_of_match
,
241 .probe
= osd101t2587_panel_probe
,
242 .remove
= osd101t2587_panel_remove
,
243 .shutdown
= osd101t2587_panel_shutdown
,
245 module_mipi_dsi_driver(osd101t2587_panel_driver
);
247 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
248 MODULE_DESCRIPTION("OSD101T2587-53TS DSI panel");
249 MODULE_LICENSE("GPL v2");