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/gpio/consumer.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/regulator/consumer.h>
15 
16 #include <drm/drmP.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_mipi_dsi.h>
19 #include <drm/drm_panel.h>
20 
21 #include <video/mipi_display.h>
22 
23 struct sharp_nt_panel {
24 	struct drm_panel base;
25 	struct mipi_dsi_device *dsi;
26 
27 	struct backlight_device *backlight;
28 	struct regulator *supply;
29 	struct gpio_desc *reset_gpio;
30 
31 	bool prepared;
32 	bool enabled;
33 
34 	const struct drm_display_mode *mode;
35 };
36 
37 static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
38 {
39 	return container_of(panel, struct sharp_nt_panel, base);
40 }
41 
42 static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
43 {
44 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
45 	int ret;
46 
47 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
48 
49 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
50 	if (ret < 0)
51 		return ret;
52 
53 	msleep(120);
54 
55 	/* Novatek two-lane operation */
56 	ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
57 	if (ret < 0)
58 		return ret;
59 
60 	/* Set both MCU and RGB I/F to 24bpp */
61 	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
62 					(MIPI_DCS_PIXEL_FMT_24BIT << 4));
63 	if (ret < 0)
64 		return ret;
65 
66 	return 0;
67 }
68 
69 static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
70 {
71 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
72 	int ret;
73 
74 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
75 
76 	ret = mipi_dsi_dcs_set_display_on(dsi);
77 	if (ret < 0)
78 		return ret;
79 
80 	return 0;
81 }
82 
83 static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
84 {
85 	struct mipi_dsi_device *dsi = sharp_nt->dsi;
86 	int ret;
87 
88 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
89 
90 	ret = mipi_dsi_dcs_set_display_off(dsi);
91 	if (ret < 0)
92 		return ret;
93 
94 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
95 	if (ret < 0)
96 		return ret;
97 
98 	return 0;
99 }
100 
101 
102 static int sharp_nt_panel_disable(struct drm_panel *panel)
103 {
104 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
105 
106 	if (!sharp_nt->enabled)
107 		return 0;
108 
109 	backlight_disable(sharp_nt->backlight);
110 
111 	sharp_nt->enabled = false;
112 
113 	return 0;
114 }
115 
116 static int sharp_nt_panel_unprepare(struct drm_panel *panel)
117 {
118 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
119 	int ret;
120 
121 	if (!sharp_nt->prepared)
122 		return 0;
123 
124 	ret = sharp_nt_panel_off(sharp_nt);
125 	if (ret < 0) {
126 		dev_err(panel->dev, "failed to set panel off: %d\n", ret);
127 		return ret;
128 	}
129 
130 	regulator_disable(sharp_nt->supply);
131 	if (sharp_nt->reset_gpio)
132 		gpiod_set_value(sharp_nt->reset_gpio, 0);
133 
134 	sharp_nt->prepared = false;
135 
136 	return 0;
137 }
138 
139 static int sharp_nt_panel_prepare(struct drm_panel *panel)
140 {
141 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
142 	int ret;
143 
144 	if (sharp_nt->prepared)
145 		return 0;
146 
147 	ret = regulator_enable(sharp_nt->supply);
148 	if (ret < 0)
149 		return ret;
150 
151 	msleep(20);
152 
153 	if (sharp_nt->reset_gpio) {
154 		gpiod_set_value(sharp_nt->reset_gpio, 1);
155 		msleep(1);
156 		gpiod_set_value(sharp_nt->reset_gpio, 0);
157 		msleep(1);
158 		gpiod_set_value(sharp_nt->reset_gpio, 1);
159 		msleep(10);
160 	}
161 
162 	ret = sharp_nt_panel_init(sharp_nt);
163 	if (ret < 0) {
164 		dev_err(panel->dev, "failed to init panel: %d\n", ret);
165 		goto poweroff;
166 	}
167 
168 	ret = sharp_nt_panel_on(sharp_nt);
169 	if (ret < 0) {
170 		dev_err(panel->dev, "failed to set panel on: %d\n", ret);
171 		goto poweroff;
172 	}
173 
174 	sharp_nt->prepared = true;
175 
176 	return 0;
177 
178 poweroff:
179 	regulator_disable(sharp_nt->supply);
180 	if (sharp_nt->reset_gpio)
181 		gpiod_set_value(sharp_nt->reset_gpio, 0);
182 	return ret;
183 }
184 
185 static int sharp_nt_panel_enable(struct drm_panel *panel)
186 {
187 	struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
188 
189 	if (sharp_nt->enabled)
190 		return 0;
191 
192 	backlight_enable(sharp_nt->backlight);
193 
194 	sharp_nt->enabled = true;
195 
196 	return 0;
197 }
198 
199 static const struct drm_display_mode default_mode = {
200 	.clock = 41118,
201 	.hdisplay = 540,
202 	.hsync_start = 540 + 48,
203 	.hsync_end = 540 + 48 + 80,
204 	.htotal = 540 + 48 + 80 + 32,
205 	.vdisplay = 960,
206 	.vsync_start = 960 + 3,
207 	.vsync_end = 960 + 3 + 15,
208 	.vtotal = 960 + 3 + 15 + 1,
209 	.vrefresh = 60,
210 };
211 
212 static int sharp_nt_panel_get_modes(struct drm_panel *panel)
213 {
214 	struct drm_display_mode *mode;
215 
216 	mode = drm_mode_duplicate(panel->drm, &default_mode);
217 	if (!mode) {
218 		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
219 				default_mode.hdisplay, default_mode.vdisplay,
220 				default_mode.vrefresh);
221 		return -ENOMEM;
222 	}
223 
224 	drm_mode_set_name(mode);
225 
226 	drm_mode_probed_add(panel->connector, mode);
227 
228 	panel->connector->display_info.width_mm = 54;
229 	panel->connector->display_info.height_mm = 95;
230 
231 	return 1;
232 }
233 
234 static const struct drm_panel_funcs sharp_nt_panel_funcs = {
235 	.disable = sharp_nt_panel_disable,
236 	.unprepare = sharp_nt_panel_unprepare,
237 	.prepare = sharp_nt_panel_prepare,
238 	.enable = sharp_nt_panel_enable,
239 	.get_modes = sharp_nt_panel_get_modes,
240 };
241 
242 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
243 {
244 	struct device *dev = &sharp_nt->dsi->dev;
245 
246 	sharp_nt->mode = &default_mode;
247 
248 	sharp_nt->supply = devm_regulator_get(dev, "avdd");
249 	if (IS_ERR(sharp_nt->supply))
250 		return PTR_ERR(sharp_nt->supply);
251 
252 	sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
253 	if (IS_ERR(sharp_nt->reset_gpio)) {
254 		dev_err(dev, "cannot get reset-gpios %ld\n",
255 			PTR_ERR(sharp_nt->reset_gpio));
256 		sharp_nt->reset_gpio = NULL;
257 	} else {
258 		gpiod_set_value(sharp_nt->reset_gpio, 0);
259 	}
260 
261 	sharp_nt->backlight = devm_of_find_backlight(dev);
262 
263 	if (IS_ERR(sharp_nt->backlight))
264 		return PTR_ERR(sharp_nt->backlight);
265 
266 	drm_panel_init(&sharp_nt->base);
267 	sharp_nt->base.funcs = &sharp_nt_panel_funcs;
268 	sharp_nt->base.dev = &sharp_nt->dsi->dev;
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