Merge tag 'sound-5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[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 };
205
206 static int sharp_nt_panel_get_modes(struct drm_panel *panel,
207                                     struct drm_connector *connector)
208 {
209         struct drm_display_mode *mode;
210
211         mode = drm_mode_duplicate(connector->dev, &default_mode);
212         if (!mode) {
213                 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
214                         default_mode.hdisplay, default_mode.vdisplay,
215                         drm_mode_vrefresh(&default_mode));
216                 return -ENOMEM;
217         }
218
219         drm_mode_set_name(mode);
220
221         drm_mode_probed_add(connector, mode);
222
223         connector->display_info.width_mm = 54;
224         connector->display_info.height_mm = 95;
225
226         return 1;
227 }
228
229 static const struct drm_panel_funcs sharp_nt_panel_funcs = {
230         .disable = sharp_nt_panel_disable,
231         .unprepare = sharp_nt_panel_unprepare,
232         .prepare = sharp_nt_panel_prepare,
233         .enable = sharp_nt_panel_enable,
234         .get_modes = sharp_nt_panel_get_modes,
235 };
236
237 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
238 {
239         struct device *dev = &sharp_nt->dsi->dev;
240         int ret;
241
242         sharp_nt->mode = &default_mode;
243
244         sharp_nt->supply = devm_regulator_get(dev, "avdd");
245         if (IS_ERR(sharp_nt->supply))
246                 return PTR_ERR(sharp_nt->supply);
247
248         sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
249         if (IS_ERR(sharp_nt->reset_gpio)) {
250                 dev_err(dev, "cannot get reset-gpios %ld\n",
251                         PTR_ERR(sharp_nt->reset_gpio));
252                 sharp_nt->reset_gpio = NULL;
253         } else {
254                 gpiod_set_value(sharp_nt->reset_gpio, 0);
255         }
256
257         drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev,
258                        &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI);
259
260         ret = drm_panel_of_backlight(&sharp_nt->base);
261         if (ret)
262                 return ret;
263
264         drm_panel_add(&sharp_nt->base);
265
266         return 0;
267 }
268
269 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
270 {
271         if (sharp_nt->base.dev)
272                 drm_panel_remove(&sharp_nt->base);
273 }
274
275 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
276 {
277         struct sharp_nt_panel *sharp_nt;
278         int ret;
279
280         dsi->lanes = 2;
281         dsi->format = MIPI_DSI_FMT_RGB888;
282         dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
283                         MIPI_DSI_MODE_VIDEO_HSE |
284                         MIPI_DSI_CLOCK_NON_CONTINUOUS |
285                         MIPI_DSI_MODE_EOT_PACKET;
286
287         sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
288         if (!sharp_nt)
289                 return -ENOMEM;
290
291         mipi_dsi_set_drvdata(dsi, sharp_nt);
292
293         sharp_nt->dsi = dsi;
294
295         ret = sharp_nt_panel_add(sharp_nt);
296         if (ret < 0)
297                 return ret;
298
299         return mipi_dsi_attach(dsi);
300 }
301
302 static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
303 {
304         struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
305         int ret;
306
307         ret = drm_panel_disable(&sharp_nt->base);
308         if (ret < 0)
309                 dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
310
311         ret = mipi_dsi_detach(dsi);
312         if (ret < 0)
313                 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
314
315         sharp_nt_panel_del(sharp_nt);
316
317         return 0;
318 }
319
320 static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
321 {
322         struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
323
324         drm_panel_disable(&sharp_nt->base);
325 }
326
327 static const struct of_device_id sharp_nt_of_match[] = {
328         { .compatible = "sharp,ls043t1le01-qhd", },
329         { }
330 };
331 MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
332
333 static struct mipi_dsi_driver sharp_nt_panel_driver = {
334         .driver = {
335                 .name = "panel-sharp-ls043t1le01-qhd",
336                 .of_match_table = sharp_nt_of_match,
337         },
338         .probe = sharp_nt_panel_probe,
339         .remove = sharp_nt_panel_remove,
340         .shutdown = sharp_nt_panel_shutdown,
341 };
342 module_mipi_dsi_driver(sharp_nt_panel_driver);
343
344 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
345 MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
346 MODULE_LICENSE("GPL v2");