]> Git Repo - linux.git/blob - drivers/gpu/drm/tinydrm/hx8357d.c
Merge branch 'drm-next-5.1' of git://people.freedesktop.org/~agd5f/linux into drm...
[linux.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 <[email protected]>
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_drv.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_gem_framebuffer_helper.h>
22 #include <drm/drm_modeset_helper.h>
23 #include <drm/tinydrm/mipi-dbi.h>
24 #include <drm/tinydrm/tinydrm-helpers.h>
25 #include <video/mipi_display.h>
26
27 #define HX8357D_SETOSC 0xb0
28 #define HX8357D_SETPOWER 0xb1
29 #define HX8357D_SETRGB 0xb3
30 #define HX8357D_SETCYC 0xb3
31 #define HX8357D_SETCOM 0xb6
32 #define HX8357D_SETEXTC 0xb9
33 #define HX8357D_SETSTBA 0xc0
34 #define HX8357D_SETPANEL 0xcc
35 #define HX8357D_SETGAMMA 0xe0
36
37 #define HX8357D_MADCTL_MY  0x80
38 #define HX8357D_MADCTL_MX  0x40
39 #define HX8357D_MADCTL_MV  0x20
40 #define HX8357D_MADCTL_ML  0x10
41 #define HX8357D_MADCTL_RGB 0x00
42 #define HX8357D_MADCTL_BGR 0x08
43 #define HX8357D_MADCTL_MH  0x04
44
45 static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
46                              struct drm_crtc_state *crtc_state,
47                              struct drm_plane_state *plane_state)
48 {
49         struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
50         struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
51         u8 addr_mode;
52         int ret;
53
54         DRM_DEBUG_KMS("\n");
55
56         ret = mipi_dbi_poweron_conditional_reset(mipi);
57         if (ret < 0)
58                 return;
59         if (ret == 1)
60                 goto out_enable;
61
62         /* setextc */
63         mipi_dbi_command(mipi, HX8357D_SETEXTC, 0xFF, 0x83, 0x57);
64         msleep(150);
65
66         /* setRGB which also enables SDO */
67         mipi_dbi_command(mipi, HX8357D_SETRGB, 0x00, 0x00, 0x06, 0x06);
68
69         /* -1.52V */
70         mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
71
72         /* Normal mode 70Hz, Idle mode 55 Hz */
73         mipi_dbi_command(mipi, HX8357D_SETOSC, 0x68);
74
75         /* Set Panel - BGR, Gate direction swapped */
76         mipi_dbi_command(mipi, HX8357D_SETPANEL, 0x05);
77
78         mipi_dbi_command(mipi, HX8357D_SETPOWER,
79                          0x00,  /* Not deep standby */
80                          0x15,  /* BT */
81                          0x1C,  /* VSPR */
82                          0x1C,  /* VSNR */
83                          0x83,  /* AP */
84                          0xAA);  /* FS */
85
86         mipi_dbi_command(mipi, HX8357D_SETSTBA,
87                          0x50,  /* OPON normal */
88                          0x50,  /* OPON idle */
89                          0x01,  /* STBA */
90                          0x3C,  /* STBA */
91                          0x1E,  /* STBA */
92                          0x08);  /* GEN */
93
94         mipi_dbi_command(mipi, HX8357D_SETCYC,
95                          0x02,  /* NW 0x02 */
96                          0x40,  /* RTN */
97                          0x00,  /* DIV */
98                          0x2A,  /* DUM */
99                          0x2A,  /* DUM */
100                          0x0D,  /* GDON */
101                          0x78);  /* GDOFF */
102
103         mipi_dbi_command(mipi, HX8357D_SETGAMMA,
104                          0x02,
105                          0x0A,
106                          0x11,
107                          0x1d,
108                          0x23,
109                          0x35,
110                          0x41,
111                          0x4b,
112                          0x4b,
113                          0x42,
114                          0x3A,
115                          0x27,
116                          0x1B,
117                          0x08,
118                          0x09,
119                          0x03,
120                          0x02,
121                          0x0A,
122                          0x11,
123                          0x1d,
124                          0x23,
125                          0x35,
126                          0x41,
127                          0x4b,
128                          0x4b,
129                          0x42,
130                          0x3A,
131                          0x27,
132                          0x1B,
133                          0x08,
134                          0x09,
135                          0x03,
136                          0x00,
137                          0x01);
138
139         /* 16 bit */
140         mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
141                          MIPI_DCS_PIXEL_FMT_16BIT);
142
143         /* TE off */
144         mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
145
146         /* tear line */
147         mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
148
149         /* Exit Sleep */
150         mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
151         msleep(150);
152
153         /* display on */
154         mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
155         usleep_range(5000, 7000);
156
157 out_enable:
158         switch (mipi->rotation) {
159         default:
160                 addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
161                 break;
162         case 90:
163                 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
164                 break;
165         case 180:
166                 addr_mode = 0;
167                 break;
168         case 270:
169                 addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
170                 break;
171         }
172         mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
173         mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
174 }
175
176 static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
177         .enable = yx240qv29_enable,
178         .disable = mipi_dbi_pipe_disable,
179         .update = mipi_dbi_pipe_update,
180         .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
181 };
182
183 static const struct drm_display_mode yx350hv15_mode = {
184         TINYDRM_MODE(320, 480, 60, 75),
185 };
186
187 DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
188
189 static struct drm_driver hx8357d_driver = {
190         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
191         .fops                   = &hx8357d_fops,
192         DRM_GEM_CMA_VMAP_DRIVER_OPS,
193         .debugfs_init           = mipi_dbi_debugfs_init,
194         .name                   = "hx8357d",
195         .desc                   = "HX8357D",
196         .date                   = "20181023",
197         .major                  = 1,
198         .minor                  = 0,
199 };
200
201 static const struct of_device_id hx8357d_of_match[] = {
202         { .compatible = "adafruit,yx350hv15" },
203         { }
204 };
205 MODULE_DEVICE_TABLE(of, hx8357d_of_match);
206
207 static const struct spi_device_id hx8357d_id[] = {
208         { "yx350hv15", 0 },
209         { }
210 };
211 MODULE_DEVICE_TABLE(spi, hx8357d_id);
212
213 static int hx8357d_probe(struct spi_device *spi)
214 {
215         struct device *dev = &spi->dev;
216         struct mipi_dbi *mipi;
217         struct gpio_desc *dc;
218         u32 rotation = 0;
219         int ret;
220
221         mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
222         if (!mipi)
223                 return -ENOMEM;
224
225         dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
226         if (IS_ERR(dc)) {
227                 DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
228                 return PTR_ERR(dc);
229         }
230
231         mipi->backlight = devm_of_find_backlight(dev);
232         if (IS_ERR(mipi->backlight))
233                 return PTR_ERR(mipi->backlight);
234
235         device_property_read_u32(dev, "rotation", &rotation);
236
237         ret = mipi_dbi_spi_init(spi, mipi, dc);
238         if (ret)
239                 return ret;
240
241         ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
242                             &hx8357d_driver, &yx350hv15_mode, rotation);
243         if (ret)
244                 return ret;
245
246         spi_set_drvdata(spi, mipi);
247
248         return devm_tinydrm_register(&mipi->tinydrm);
249 }
250
251 static void hx8357d_shutdown(struct spi_device *spi)
252 {
253         struct mipi_dbi *mipi = spi_get_drvdata(spi);
254
255         tinydrm_shutdown(&mipi->tinydrm);
256 }
257
258 static struct spi_driver hx8357d_spi_driver = {
259         .driver = {
260                 .name = "hx8357d",
261                 .of_match_table = hx8357d_of_match,
262         },
263         .id_table = hx8357d_id,
264         .probe = hx8357d_probe,
265         .shutdown = hx8357d_shutdown,
266 };
267 module_spi_driver(hx8357d_spi_driver);
268
269 MODULE_DESCRIPTION("HX8357D DRM driver");
270 MODULE_AUTHOR("Eric Anholt <[email protected]>");
271 MODULE_LICENSE("GPL");
This page took 0.045371 seconds and 4 git commands to generate.