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