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