drm/panel: Initialise panel dev and funcs through drm_panel_init()
[linux-2.6-block.git] / drivers / gpu / drm / panel / panel-sharp-ls043t1le01.c
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);
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");