1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2015 Red Hat
4 * Copyright (C) 2015 Sony Mobile Communications Inc.
5 * Author: Werner Johansson <werner.johansson@sonymobile.com>
7 * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
10 #include <linux/delay.h>
11 #include <linux/module.h>
13 #include <linux/regulator/consumer.h>
15 #include <video/mipi_display.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_device.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_panel.h>
23 * When power is turned off to this panel a minimum off time of 500ms has to be
24 * observed before powering back on as there's no external reset pin. Keep
25 * track of earliest wakeup time and delay subsequent prepare call accordingly
27 #define MIN_POFF_MS (500)
29 struct wuxga_nt_panel
{
30 struct drm_panel base
;
31 struct mipi_dsi_device
*dsi
;
33 struct regulator
*supply
;
38 ktime_t earliest_wake
;
40 const struct drm_display_mode
*mode
;
43 static inline struct wuxga_nt_panel
*to_wuxga_nt_panel(struct drm_panel
*panel
)
45 return container_of(panel
, struct wuxga_nt_panel
, base
);
48 static int wuxga_nt_panel_on(struct wuxga_nt_panel
*wuxga_nt
)
50 return mipi_dsi_turn_on_peripheral(wuxga_nt
->dsi
);
53 static int wuxga_nt_panel_disable(struct drm_panel
*panel
)
55 struct wuxga_nt_panel
*wuxga_nt
= to_wuxga_nt_panel(panel
);
56 int mipi_ret
, bl_ret
= 0;
58 if (!wuxga_nt
->enabled
)
61 mipi_ret
= mipi_dsi_shutdown_peripheral(wuxga_nt
->dsi
);
63 wuxga_nt
->enabled
= false;
65 return mipi_ret
? mipi_ret
: bl_ret
;
68 static int wuxga_nt_panel_unprepare(struct drm_panel
*panel
)
70 struct wuxga_nt_panel
*wuxga_nt
= to_wuxga_nt_panel(panel
);
72 if (!wuxga_nt
->prepared
)
75 regulator_disable(wuxga_nt
->supply
);
76 wuxga_nt
->earliest_wake
= ktime_add_ms(ktime_get_real(), MIN_POFF_MS
);
77 wuxga_nt
->prepared
= false;
82 static int wuxga_nt_panel_prepare(struct drm_panel
*panel
)
84 struct wuxga_nt_panel
*wuxga_nt
= to_wuxga_nt_panel(panel
);
88 if (wuxga_nt
->prepared
)
92 * If the user re-enabled the panel before the required off-time then
93 * we need to wait the remaining period before re-enabling regulator
95 enablewait
= ktime_ms_delta(wuxga_nt
->earliest_wake
, ktime_get_real());
97 /* Sanity check, this should never happen */
98 if (enablewait
> MIN_POFF_MS
)
99 enablewait
= MIN_POFF_MS
;
104 ret
= regulator_enable(wuxga_nt
->supply
);
109 * A minimum delay of 250ms is required after power-up until commands
114 ret
= wuxga_nt_panel_on(wuxga_nt
);
116 dev_err(panel
->dev
, "failed to set panel on: %d\n", ret
);
120 wuxga_nt
->prepared
= true;
125 regulator_disable(wuxga_nt
->supply
);
130 static int wuxga_nt_panel_enable(struct drm_panel
*panel
)
132 struct wuxga_nt_panel
*wuxga_nt
= to_wuxga_nt_panel(panel
);
134 if (wuxga_nt
->enabled
)
137 wuxga_nt
->enabled
= true;
142 static const struct drm_display_mode default_mode
= {
145 .hsync_start
= 1920 + 152,
146 .hsync_end
= 1920 + 152 + 52,
147 .htotal
= 1920 + 152 + 52 + 20,
149 .vsync_start
= 1200 + 24,
150 .vsync_end
= 1200 + 24 + 6,
151 .vtotal
= 1200 + 24 + 6 + 48,
155 static int wuxga_nt_panel_get_modes(struct drm_panel
*panel
,
156 struct drm_connector
*connector
)
158 struct drm_display_mode
*mode
;
160 mode
= drm_mode_duplicate(connector
->dev
, &default_mode
);
162 dev_err(panel
->dev
, "failed to add mode %ux%u@%u\n",
163 default_mode
.hdisplay
, default_mode
.vdisplay
,
164 default_mode
.vrefresh
);
168 drm_mode_set_name(mode
);
170 drm_mode_probed_add(connector
, mode
);
172 connector
->display_info
.width_mm
= 217;
173 connector
->display_info
.height_mm
= 136;
178 static const struct drm_panel_funcs wuxga_nt_panel_funcs
= {
179 .disable
= wuxga_nt_panel_disable
,
180 .unprepare
= wuxga_nt_panel_unprepare
,
181 .prepare
= wuxga_nt_panel_prepare
,
182 .enable
= wuxga_nt_panel_enable
,
183 .get_modes
= wuxga_nt_panel_get_modes
,
186 static const struct of_device_id wuxga_nt_of_match
[] = {
187 { .compatible
= "panasonic,vvx10f034n00", },
190 MODULE_DEVICE_TABLE(of
, wuxga_nt_of_match
);
192 static int wuxga_nt_panel_add(struct wuxga_nt_panel
*wuxga_nt
)
194 struct device
*dev
= &wuxga_nt
->dsi
->dev
;
197 wuxga_nt
->mode
= &default_mode
;
199 wuxga_nt
->supply
= devm_regulator_get(dev
, "power");
200 if (IS_ERR(wuxga_nt
->supply
))
201 return PTR_ERR(wuxga_nt
->supply
);
203 drm_panel_init(&wuxga_nt
->base
, &wuxga_nt
->dsi
->dev
,
204 &wuxga_nt_panel_funcs
, DRM_MODE_CONNECTOR_DSI
);
206 ret
= drm_panel_of_backlight(&wuxga_nt
->base
);
210 return drm_panel_add(&wuxga_nt
->base
);
213 static void wuxga_nt_panel_del(struct wuxga_nt_panel
*wuxga_nt
)
215 if (wuxga_nt
->base
.dev
)
216 drm_panel_remove(&wuxga_nt
->base
);
219 static int wuxga_nt_panel_probe(struct mipi_dsi_device
*dsi
)
221 struct wuxga_nt_panel
*wuxga_nt
;
225 dsi
->format
= MIPI_DSI_FMT_RGB888
;
226 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
|
227 MIPI_DSI_MODE_VIDEO_HSE
|
228 MIPI_DSI_CLOCK_NON_CONTINUOUS
|
231 wuxga_nt
= devm_kzalloc(&dsi
->dev
, sizeof(*wuxga_nt
), GFP_KERNEL
);
235 mipi_dsi_set_drvdata(dsi
, wuxga_nt
);
239 ret
= wuxga_nt_panel_add(wuxga_nt
);
243 return mipi_dsi_attach(dsi
);
246 static int wuxga_nt_panel_remove(struct mipi_dsi_device
*dsi
)
248 struct wuxga_nt_panel
*wuxga_nt
= mipi_dsi_get_drvdata(dsi
);
251 ret
= drm_panel_disable(&wuxga_nt
->base
);
253 dev_err(&dsi
->dev
, "failed to disable panel: %d\n", ret
);
255 ret
= mipi_dsi_detach(dsi
);
257 dev_err(&dsi
->dev
, "failed to detach from DSI host: %d\n", ret
);
259 wuxga_nt_panel_del(wuxga_nt
);
264 static void wuxga_nt_panel_shutdown(struct mipi_dsi_device
*dsi
)
266 struct wuxga_nt_panel
*wuxga_nt
= mipi_dsi_get_drvdata(dsi
);
268 drm_panel_disable(&wuxga_nt
->base
);
271 static struct mipi_dsi_driver wuxga_nt_panel_driver
= {
273 .name
= "panel-panasonic-vvx10f034n00",
274 .of_match_table
= wuxga_nt_of_match
,
276 .probe
= wuxga_nt_panel_probe
,
277 .remove
= wuxga_nt_panel_remove
,
278 .shutdown
= wuxga_nt_panel_shutdown
,
280 module_mipi_dsi_driver(wuxga_nt_panel_driver
);
282 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
283 MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
284 MODULE_LICENSE("GPL v2");