Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / tinydrm / hx8357d.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * DRM driver for the HX8357D LCD controller
4  *
5  * Copyright 2018 Broadcom
6  * Copyright 2018 David Lechner <david@lechnology.com>
7  * Copyright 2016 Noralf Trønnes
8  * Copyright (C) 2015 Adafruit Industries
9  * Copyright (C) 2013 Christian Vogelgsang
10  */
11
12 #include <linux/backlight.h>
13 #include <linux/delay.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/module.h>
16 #include <linux/property.h>
17 #include <linux/spi/spi.h>
18
19 #include <drm/drm_atomic_helper.h>
20 #include <drm/drm_drv.h>
21 #include <drm/drm_fb_helper.h>
22 #include <drm/drm_gem_cma_helper.h>
23 #include <drm/drm_gem_framebuffer_helper.h>
24 #include <drm/drm_modeset_helper.h>
25 #include <drm/tinydrm/mipi-dbi.h>
26 #include <drm/tinydrm/tinydrm-helpers.h>
27 #include <video/mipi_display.h>
28
29 #define HX8357D_SETOSC 0xb0
30 #define HX8357D_SETPOWER 0xb1
31 #define HX8357D_SETRGB 0xb3
32 #define HX8357D_SETCYC 0xb3
33 #define HX8357D_SETCOM 0xb6
34 #define HX8357D_SETEXTC 0xb9
35 #define HX8357D_SETSTBA 0xc0
36 #define HX8357D_SETPANEL 0xcc
37 #define HX8357D_SETGAMMA 0xe0
38
39 #define HX8357D_MADCTL_MY  0x80
40 #define HX8357D_MADCTL_MX  0x40
41 #define HX8357D_MADCTL_MV  0x20
42 #define HX8357D_MADCTL_ML  0x10
43 #define HX8357D_MADCTL_RGB 0x00
44 #define HX8357D_MADCTL_BGR 0x08
45 #define HX8357D_MADCTL_MH  0x04
46
47 static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
48                              struct drm_crtc_state *crtc_state,
49                              struct drm_plane_state *plane_state)
50 {
51         struct mipi_dbi *mipi = drm_to_mipi_dbi(pipe->crtc.dev);
52         u8 addr_mode;
53         int ret, idx;
54
55         if (!drm_dev_enter(pipe->crtc.dev, &idx))
56                 return;
57
58         DRM_DEBUG_KMS("\n");
59
60         ret = mipi_dbi_poweron_conditional_reset(mipi);
61         if (ret < 0)
62                 goto out_exit;
63         if (ret == 1)
64                 goto out_enable;
65
66         /* setextc */
67         mipi_dbi_command(mipi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
68         msleep(150);
69
70         /* setRGB which also enables SDO */
71         mipi_dbi_command(mipi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
72
73         /* -1.52V */
74         mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
75
76         /* Normal mode 70Hz, Idle mode 55 Hz */
77         mipi_dbi_command(mipi, HX8357D_SETOSC, 0x68);
78
79         /* Set Panel - BGR, Gate direction swapped */
80         mipi_dbi_command(mipi, HX8357D_SETPANEL, 0x05);
81
82         mipi_dbi_command(mipi, HX8357D_SETPOWER,
83                          0x00,  /* Not deep standby */
84                          0x15,  /* BT */
85                          0x1C,  /* VSPR */
86                          0x1C,  /* VSNR */
87                          0x83,  /* AP */
88                          0xAA);  /* FS */
89
90         mipi_dbi_command(mipi, HX8357D_SETSTBA,
91                          0x50,  /* OPON normal */
92                          0x50,  /* OPON idle */
93                          0x01,  /* STBA */
94                          0x3C,  /* STBA */
95                          0x1E,  /* STBA */
96                          0x08);  /* GEN */
97
98         mipi_dbi_command(mipi, HX8357D_SETCYC,
99                          0x02,  /* NW 0x02 */
100                          0x40,  /* RTN */
101                          0x00,  /* DIV */
102                          0x2A,  /* DUM */
103                          0x2A,  /* DUM */
104                          0x0D,  /* GDON */
105                          0x78);  /* GDOFF */
106
107         mipi_dbi_command(mipi, HX8357D_SETGAMMA,
108                          0x02,
109                          0x0A,
110                          0x11,
111                          0x1d,
112                          0x23,
113                          0x35,
114                          0x41,
115                          0x4b,
116                          0x4b,
117                          0x42,
118                          0x3A,
119                          0x27,
120                          0x1B,
121                          0x08,
122                          0x09,
123                          0x03,
124                          0x02,
125                          0x0A,
126                          0x11,
127                          0x1d,
128                          0x23,
129                          0x35,
130                          0x41,
131                          0x4b,
132                          0x4b,
133                          0x42,
134                          0x3A,
135                          0x27,
136                          0x1B,
137                          0x08,
138                          0x09,
139                          0x03,
140                          0x00,
141                          0x01);
142
143         /* 16 bit */
144         mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
145                          MIPI_DCS_PIXEL_FMT_16BIT);
146
147         /* TE off */
148         mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
149
150         /* tear line */
151         mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
152
153         /* Exit Sleep */
154         mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
155         msleep(150);
156
157         /* display on */
158         mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
159         usleep_range(5000, 7000);
160
161 out_enable:
162         switch (mipi->rotation) {
163         default:
164                 addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
165                 break;
166         case 90:
167                 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
168                 break;
169         case 180:
170                 addr_mode = 0;
171                 break;
172         case 270:
173                 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
174                 break;
175         }
176         mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
177         mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
178 out_exit:
179         drm_dev_exit(idx);
180 }
181
182 static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
183         .enable = yx240qv29_enable,
184         .disable = mipi_dbi_pipe_disable,
185         .update = mipi_dbi_pipe_update,
186         .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
187 };
188
189 static const struct drm_display_mode yx350hv15_mode = {
190         DRM_SIMPLE_MODE(320, 480, 60, 75),
191 };
192
193 DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
194
195 static struct drm_driver hx8357d_driver = {
196         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
197         .fops                   = &hx8357d_fops,
198         .release                = mipi_dbi_release,
199         DRM_GEM_CMA_VMAP_DRIVER_OPS,
200         .debugfs_init           = mipi_dbi_debugfs_init,
201         .name                   = "hx8357d",
202         .desc                   = "HX8357D",
203         .date                   = "20181023",
204         .major                  = 1,
205         .minor                  = 0,
206 };
207
208 static const struct of_device_id hx8357d_of_match[] = {
209         { .compatible = "adafruit,yx350hv15" },
210         { }
211 };
212 MODULE_DEVICE_TABLE(of, hx8357d_of_match);
213
214 static const struct spi_device_id hx8357d_id[] = {
215         { "yx350hv15", 0 },
216         { }
217 };
218 MODULE_DEVICE_TABLE(spi, hx8357d_id);
219
220 static int hx8357d_probe(struct spi_device *spi)
221 {
222         struct device *dev = &spi->dev;
223         struct drm_device *drm;
224         struct mipi_dbi *mipi;
225         struct gpio_desc *dc;
226         u32 rotation = 0;
227         int ret;
228
229         mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
230         if (!mipi)
231                 return -ENOMEM;
232
233         drm = &mipi->drm;
234         ret = devm_drm_dev_init(dev, drm, &hx8357d_driver);
235         if (ret) {
236                 kfree(mipi);
237                 return ret;
238         }
239
240         drm_mode_config_init(drm);
241
242         dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
243         if (IS_ERR(dc)) {
244                 DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
245                 return PTR_ERR(dc);
246         }
247
248         mipi->backlight = devm_of_find_backlight(dev);
249         if (IS_ERR(mipi->backlight))
250                 return PTR_ERR(mipi->backlight);
251
252         device_property_read_u32(dev, "rotation", &rotation);
253
254         ret = mipi_dbi_spi_init(spi, mipi, dc);
255         if (ret)
256                 return ret;
257
258         ret = mipi_dbi_init(mipi, &hx8357d_pipe_funcs, &yx350hv15_mode, rotation);
259         if (ret)
260                 return ret;
261
262         drm_mode_config_reset(drm);
263
264         ret = drm_dev_register(drm, 0);
265         if (ret)
266                 return ret;
267
268         spi_set_drvdata(spi, drm);
269
270         drm_fbdev_generic_setup(drm, 0);
271
272         return 0;
273 }
274
275 static int hx8357d_remove(struct spi_device *spi)
276 {
277         struct drm_device *drm = spi_get_drvdata(spi);
278
279         drm_dev_unplug(drm);
280         drm_atomic_helper_shutdown(drm);
281
282         return 0;
283 }
284
285 static void hx8357d_shutdown(struct spi_device *spi)
286 {
287         drm_atomic_helper_shutdown(spi_get_drvdata(spi));
288 }
289
290 static struct spi_driver hx8357d_spi_driver = {
291         .driver = {
292                 .name = "hx8357d",
293                 .of_match_table = hx8357d_of_match,
294         },
295         .id_table = hx8357d_id,
296         .probe = hx8357d_probe,
297         .remove = hx8357d_remove,
298         .shutdown = hx8357d_shutdown,
299 };
300 module_spi_driver(hx8357d_spi_driver);
301
302 MODULE_DESCRIPTION("HX8357D DRM driver");
303 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
304 MODULE_LICENSE("GPL");