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,
154 static int wuxga_nt_panel_get_modes(struct drm_panel
*panel
,
155 struct drm_connector
*connector
)
157 struct drm_display_mode
*mode
;
159 mode
= drm_mode_duplicate(connector
->dev
, &default_mode
);
161 dev_err(panel
->dev
, "failed to add mode %ux%u@%u\n",
162 default_mode
.hdisplay
, default_mode
.vdisplay
,
163 drm_mode_vrefresh(&default_mode
));
167 drm_mode_set_name(mode
);
169 drm_mode_probed_add(connector
, mode
);
171 connector
->display_info
.width_mm
= 217;
172 connector
->display_info
.height_mm
= 136;
177 static const struct drm_panel_funcs wuxga_nt_panel_funcs
= {
178 .disable
= wuxga_nt_panel_disable
,
179 .unprepare
= wuxga_nt_panel_unprepare
,
180 .prepare
= wuxga_nt_panel_prepare
,
181 .enable
= wuxga_nt_panel_enable
,
182 .get_modes
= wuxga_nt_panel_get_modes
,
185 static const struct of_device_id wuxga_nt_of_match
[] = {
186 { .compatible
= "panasonic,vvx10f034n00", },
189 MODULE_DEVICE_TABLE(of
, wuxga_nt_of_match
);
191 static int wuxga_nt_panel_add(struct wuxga_nt_panel
*wuxga_nt
)
193 struct device
*dev
= &wuxga_nt
->dsi
->dev
;
196 wuxga_nt
->mode
= &default_mode
;
198 wuxga_nt
->supply
= devm_regulator_get(dev
, "power");
199 if (IS_ERR(wuxga_nt
->supply
))
200 return PTR_ERR(wuxga_nt
->supply
);
202 drm_panel_init(&wuxga_nt
->base
, &wuxga_nt
->dsi
->dev
,
203 &wuxga_nt_panel_funcs
, DRM_MODE_CONNECTOR_DSI
);
205 ret
= drm_panel_of_backlight(&wuxga_nt
->base
);
209 drm_panel_add(&wuxga_nt
->base
);
214 static void wuxga_nt_panel_del(struct wuxga_nt_panel
*wuxga_nt
)
216 if (wuxga_nt
->base
.dev
)
217 drm_panel_remove(&wuxga_nt
->base
);
220 static int wuxga_nt_panel_probe(struct mipi_dsi_device
*dsi
)
222 struct wuxga_nt_panel
*wuxga_nt
;
226 dsi
->format
= MIPI_DSI_FMT_RGB888
;
227 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
|
228 MIPI_DSI_MODE_VIDEO_HSE
|
229 MIPI_DSI_CLOCK_NON_CONTINUOUS
|
232 wuxga_nt
= devm_kzalloc(&dsi
->dev
, sizeof(*wuxga_nt
), GFP_KERNEL
);
236 mipi_dsi_set_drvdata(dsi
, wuxga_nt
);
240 ret
= wuxga_nt_panel_add(wuxga_nt
);
244 return mipi_dsi_attach(dsi
);
247 static int wuxga_nt_panel_remove(struct mipi_dsi_device
*dsi
)
249 struct wuxga_nt_panel
*wuxga_nt
= mipi_dsi_get_drvdata(dsi
);
252 ret
= drm_panel_disable(&wuxga_nt
->base
);
254 dev_err(&dsi
->dev
, "failed to disable panel: %d\n", ret
);
256 ret
= mipi_dsi_detach(dsi
);
258 dev_err(&dsi
->dev
, "failed to detach from DSI host: %d\n", ret
);
260 wuxga_nt_panel_del(wuxga_nt
);
265 static void wuxga_nt_panel_shutdown(struct mipi_dsi_device
*dsi
)
267 struct wuxga_nt_panel
*wuxga_nt
= mipi_dsi_get_drvdata(dsi
);
269 drm_panel_disable(&wuxga_nt
->base
);
272 static struct mipi_dsi_driver wuxga_nt_panel_driver
= {
274 .name
= "panel-panasonic-vvx10f034n00",
275 .of_match_table
= wuxga_nt_of_match
,
277 .probe
= wuxga_nt_panel_probe
,
278 .remove
= wuxga_nt_panel_remove
,
279 .shutdown
= wuxga_nt_panel_shutdown
,
281 module_mipi_dsi_driver(wuxga_nt_panel_driver
);
283 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
284 MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
285 MODULE_LICENSE("GPL v2");