1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2015 Red Hat
4  * Copyright (C) 2015 Sony Mobile Communications Inc.
5  * Author: Werner Johansson <werner.johansson@sonymobile.com>
6  *
7  * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
8  */
9 
10 #include <linux/backlight.h>
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/regulator/consumer.h>
16 
17 #include <video/mipi_display.h>
18 
19 #include <drm/drm_crtc.h>
20 #include <drm/drm_device.h>
21 #include <drm/drm_mipi_dsi.h>
22 #include <drm/drm_panel.h>
23 
24 struct sharp_nt_panel {
25 	struct drm_panel base;
26 	struct mipi_dsi_device *dsi;
27 
28 	struct backlight_device *backlight;
29 	struct regulator *supply;
30 	struct gpio_desc *reset_gpio;
31 
32 	bool prepared;
33 	bool enabled;
34 
35 	const struct drm_display_mode *mode;
36 };
37 
38 static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
39 {
40 	return container_of(panel, struct sharp_nt_panel, base);
41 }
42 
43 static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
44 {
45 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
46 	int ret;
47 
48 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
49 
50 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
51 	if (ret < 0)
52 		return ret;
53 
54 	msleep(120);
55 
56 	/* Novatek two-lane operation */
57 	ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
58 	if (ret < 0)
59 		return ret;
60 
61 	/* Set both MCU and RGB I/F to 24bpp */
62 	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
63 					(MIPI_DCS_PIXEL_FMT_24BIT << 4));
64 	if (ret < 0)
65 		return ret;
66 
67 	return 0;
68 }
69 
70 static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
71 {
72 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
73 	int ret;
74 
75 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
76 
77 	ret = mipi_dsi_dcs_set_display_on(dsi);
78 	if (ret < 0)
79 		return ret;
80 
81 	return 0;
82 }
83 
84 static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
85 {
86 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
87 	int ret;
88 
89 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
90 
91 	ret = mipi_dsi_dcs_set_display_off(dsi);
92 	if (ret < 0)
93 		return ret;
94 
95 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
96 	if (ret < 0)
97 		return ret;
98 
99 	return 0;
100 }
101 
102 
103 static int sharp_nt_panel_disable(struct drm_panel *panel)
104 {
105 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
106 
107 	if (!sharp_nt->enabled)
108 		return 0;
109 
110 	backlight_disable(sharp_nt->backlight);
111 
112 	sharp_nt->enabled = false;
113 
114 	return 0;
115 }
116 
117 static int sharp_nt_panel_unprepare(struct drm_panel *panel)
118 {
119 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
120 	int ret;
121 
122 	if (!sharp_nt->prepared)
123 		return 0;
124 
125 	ret = sharp_nt_panel_off(sharp_nt);
126 	if (ret < 0) {
127 		dev_err(panel->dev, "failed to set panel off: %d\n", ret);
128 		return ret;
129 	}
130 
131 	regulator_disable(sharp_nt->supply);
132 	if (sharp_nt->reset_gpio)
133 		gpiod_set_value(sharp_nt->reset_gpio, 0);
134 
135 	sharp_nt->prepared = false;
136 
137 	return 0;
138 }
139 
140 static int sharp_nt_panel_prepare(struct drm_panel *panel)
141 {
142 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
143 	int ret;
144 
145 	if (sharp_nt->prepared)
146 		return 0;
147 
148 	ret = regulator_enable(sharp_nt->supply);
149 	if (ret < 0)
150 		return ret;
151 
152 	msleep(20);
153 
154 	if (sharp_nt->reset_gpio) {
155 		gpiod_set_value(sharp_nt->reset_gpio, 1);
156 		msleep(1);
157 		gpiod_set_value(sharp_nt->reset_gpio, 0);
158 		msleep(1);
159 		gpiod_set_value(sharp_nt->reset_gpio, 1);
160 		msleep(10);
161 	}
162 
163 	ret = sharp_nt_panel_init(sharp_nt);
164 	if (ret < 0) {
165 		dev_err(panel->dev, "failed to init panel: %d\n", ret);
166 		goto poweroff;
167 	}
168 
169 	ret = sharp_nt_panel_on(sharp_nt);
170 	if (ret < 0) {
171 		dev_err(panel->dev, "failed to set panel on: %d\n", ret);
172 		goto poweroff;
173 	}
174 
175 	sharp_nt->prepared = true;
176 
177 	return 0;
178 
179 poweroff:
180 	regulator_disable(sharp_nt->supply);
181 	if (sharp_nt->reset_gpio)
182 		gpiod_set_value(sharp_nt->reset_gpio, 0);
183 	return ret;
184 }
185 
186 static int sharp_nt_panel_enable(struct drm_panel *panel)
187 {
188 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
189 
190 	if (sharp_nt->enabled)
191 		return 0;
192 
193 	backlight_enable(sharp_nt->backlight);
194 
195 	sharp_nt->enabled = true;
196 
197 	return 0;
198 }
199 
200 static const struct drm_display_mode default_mode = {
201 	.clock = 41118,
202 	.hdisplay = 540,
203 	.hsync_start = 540 + 48,
204 	.hsync_end = 540 + 48 + 80,
205 	.htotal = 540 + 48 + 80 + 32,
206 	.vdisplay = 960,
207 	.vsync_start = 960 + 3,
208 	.vsync_end = 960 + 3 + 15,
209 	.vtotal = 960 + 3 + 15 + 1,
210 	.vrefresh = 60,
211 };
212 
213 static int sharp_nt_panel_get_modes(struct drm_panel *panel)
214 {
215 	struct drm_display_mode *mode;
216 
217 	mode = drm_mode_duplicate(panel->drm, &default_mode);
218 	if (!mode) {
219 		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
220 				default_mode.hdisplay, default_mode.vdisplay,
221 				default_mode.vrefresh);
222 		return -ENOMEM;
223 	}
224 
225 	drm_mode_set_name(mode);
226 
227 	drm_mode_probed_add(panel->connector, mode);
228 
229 	panel->connector->display_info.width_mm = 54;
230 	panel->connector->display_info.height_mm = 95;
231 
232 	return 1;
233 }
234 
235 static const struct drm_panel_funcs sharp_nt_panel_funcs = {
236 	.disable = sharp_nt_panel_disable,
237 	.unprepare = sharp_nt_panel_unprepare,
238 	.prepare = sharp_nt_panel_prepare,
239 	.enable = sharp_nt_panel_enable,
240 	.get_modes = sharp_nt_panel_get_modes,
241 };
242 
243 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
244 {
245 	struct device *dev = &sharp_nt->dsi->dev;
246 
247 	sharp_nt->mode = &default_mode;
248 
249 	sharp_nt->supply = devm_regulator_get(dev, "avdd");
250 	if (IS_ERR(sharp_nt->supply))
251 		return PTR_ERR(sharp_nt->supply);
252 
253 	sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
254 	if (IS_ERR(sharp_nt->reset_gpio)) {
255 		dev_err(dev, "cannot get reset-gpios %ld\n",
256 			PTR_ERR(sharp_nt->reset_gpio));
257 		sharp_nt->reset_gpio = NULL;
258 	} else {
259 		gpiod_set_value(sharp_nt->reset_gpio, 0);
260 	}
261 
262 	sharp_nt->backlight = devm_of_find_backlight(dev);
263 
264 	if (IS_ERR(sharp_nt->backlight))
265 		return PTR_ERR(sharp_nt->backlight);
266 
267 	drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
268 		       &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
269 
270 	return drm_panel_add(&sharp_nt->base);
271 }
272 
273 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
274 {
275 	if (sharp_nt->base.dev)
276 		drm_panel_remove(&sharp_nt->base);
277 }
278 
279 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
280 {
281 	struct sharp_nt_panel *sharp_nt;
282 	int ret;
283 
284 	dsi->lanes = 2;
285 	dsi->format = MIPI_DSI_FMT_RGB888;
286 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
287 			MIPI_DSI_MODE_VIDEO_HSE |
288 			MIPI_DSI_CLOCK_NON_CONTINUOUS |
289 			MIPI_DSI_MODE_EOT_PACKET;
290 
291 	sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
292 	if (!sharp_nt)
293 		return -ENOMEM;
294 
295 	mipi_dsi_set_drvdata(dsi, sharp_nt);
296 
297 	sharp_nt->dsi = dsi;
298 
299 	ret = sharp_nt_panel_add(sharp_nt);
300 	if (ret < 0)
301 		return ret;
302 
303 	return mipi_dsi_attach(dsi);
304 }
305 
306 static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
307 {
308 	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
309 	int ret;
310 
311 	ret = sharp_nt_panel_disable(&sharp_nt->base);
312 	if (ret < 0)
313 		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
314 
315 	ret = mipi_dsi_detach(dsi);
316 	if (ret < 0)
317 		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
318 
319 	sharp_nt_panel_del(sharp_nt);
320 
321 	return 0;
322 }
323 
324 static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
325 {
326 	struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
327 
328 	sharp_nt_panel_disable(&sharp_nt->base);
329 }
330 
331 static const struct of_device_id sharp_nt_of_match[] = {
332 	{ .compatible = "sharp,ls043t1le01-qhd", },
333 	{ }
334 };
335 MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
336 
337 static struct mipi_dsi_driver sharp_nt_panel_driver = {
338 	.driver = {
339 		.name = "panel-sharp-ls043t1le01-qhd",
340 		.of_match_table = sharp_nt_of_match,
341 	},
342 	.probe = sharp_nt_panel_probe,
343 	.remove = sharp_nt_panel_remove,
344 	.shutdown = sharp_nt_panel_shutdown,
345 };
346 module_mipi_dsi_driver(sharp_nt_panel_driver);
347 
348 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
349 MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
350 MODULE_LICENSE("GPL v2");
351