1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * DRM driver for display panels connected to a Sitronix ST7715R or ST7735R
4*4882a593Smuzhiyun * display controller in SPI mode.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 2017 David Lechner <david@lechnology.com>
7*4882a593Smuzhiyun * Copyright (C) 2019 Glider bvba
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/backlight.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/dma-buf.h>
13*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/property.h>
16*4882a593Smuzhiyun #include <linux/spi/spi.h>
17*4882a593Smuzhiyun #include <video/mipi_display.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
20*4882a593Smuzhiyun #include <drm/drm_drv.h>
21*4882a593Smuzhiyun #include <drm/drm_fb_helper.h>
22*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
23*4882a593Smuzhiyun #include <drm/drm_gem_framebuffer_helper.h>
24*4882a593Smuzhiyun #include <drm/drm_managed.h>
25*4882a593Smuzhiyun #include <drm/drm_mipi_dbi.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define ST7735R_FRMCTR1 0xb1
28*4882a593Smuzhiyun #define ST7735R_FRMCTR2 0xb2
29*4882a593Smuzhiyun #define ST7735R_FRMCTR3 0xb3
30*4882a593Smuzhiyun #define ST7735R_INVCTR 0xb4
31*4882a593Smuzhiyun #define ST7735R_PWCTR1 0xc0
32*4882a593Smuzhiyun #define ST7735R_PWCTR2 0xc1
33*4882a593Smuzhiyun #define ST7735R_PWCTR3 0xc2
34*4882a593Smuzhiyun #define ST7735R_PWCTR4 0xc3
35*4882a593Smuzhiyun #define ST7735R_PWCTR5 0xc4
36*4882a593Smuzhiyun #define ST7735R_VMCTR1 0xc5
37*4882a593Smuzhiyun #define ST7735R_GAMCTRP1 0xe0
38*4882a593Smuzhiyun #define ST7735R_GAMCTRN1 0xe1
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #define ST7735R_MY BIT(7)
41*4882a593Smuzhiyun #define ST7735R_MX BIT(6)
42*4882a593Smuzhiyun #define ST7735R_MV BIT(5)
43*4882a593Smuzhiyun #define ST7735R_RGB BIT(3)
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct st7735r_cfg {
46*4882a593Smuzhiyun const struct drm_display_mode mode;
47*4882a593Smuzhiyun unsigned int left_offset;
48*4882a593Smuzhiyun unsigned int top_offset;
49*4882a593Smuzhiyun unsigned int write_only:1;
50*4882a593Smuzhiyun unsigned int rgb:1; /* RGB (vs. BGR) */
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct st7735r_priv {
54*4882a593Smuzhiyun struct mipi_dbi_dev dbidev; /* Must be first for .release() */
55*4882a593Smuzhiyun const struct st7735r_cfg *cfg;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
st7735r_pipe_enable(struct drm_simple_display_pipe * pipe,struct drm_crtc_state * crtc_state,struct drm_plane_state * plane_state)58*4882a593Smuzhiyun static void st7735r_pipe_enable(struct drm_simple_display_pipe *pipe,
59*4882a593Smuzhiyun struct drm_crtc_state *crtc_state,
60*4882a593Smuzhiyun struct drm_plane_state *plane_state)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
63*4882a593Smuzhiyun struct st7735r_priv *priv = container_of(dbidev, struct st7735r_priv,
64*4882a593Smuzhiyun dbidev);
65*4882a593Smuzhiyun struct mipi_dbi *dbi = &dbidev->dbi;
66*4882a593Smuzhiyun int ret, idx;
67*4882a593Smuzhiyun u8 addr_mode;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (!drm_dev_enter(pipe->crtc.dev, &idx))
70*4882a593Smuzhiyun return;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun DRM_DEBUG_KMS("\n");
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ret = mipi_dbi_poweron_reset(dbidev);
75*4882a593Smuzhiyun if (ret)
76*4882a593Smuzhiyun goto out_exit;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun msleep(150);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
81*4882a593Smuzhiyun msleep(500);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_FRMCTR1, 0x01, 0x2c, 0x2d);
84*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_FRMCTR2, 0x01, 0x2c, 0x2d);
85*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_FRMCTR3, 0x01, 0x2c, 0x2d, 0x01, 0x2c,
86*4882a593Smuzhiyun 0x2d);
87*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_INVCTR, 0x07);
88*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_PWCTR1, 0xa2, 0x02, 0x84);
89*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_PWCTR2, 0xc5);
90*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_PWCTR3, 0x0a, 0x00);
91*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_PWCTR4, 0x8a, 0x2a);
92*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_PWCTR5, 0x8a, 0xee);
93*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_VMCTR1, 0x0e);
94*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_EXIT_INVERT_MODE);
95*4882a593Smuzhiyun switch (dbidev->rotation) {
96*4882a593Smuzhiyun default:
97*4882a593Smuzhiyun addr_mode = ST7735R_MX | ST7735R_MY;
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun case 90:
100*4882a593Smuzhiyun addr_mode = ST7735R_MX | ST7735R_MV;
101*4882a593Smuzhiyun break;
102*4882a593Smuzhiyun case 180:
103*4882a593Smuzhiyun addr_mode = 0;
104*4882a593Smuzhiyun break;
105*4882a593Smuzhiyun case 270:
106*4882a593Smuzhiyun addr_mode = ST7735R_MY | ST7735R_MV;
107*4882a593Smuzhiyun break;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (priv->cfg->rgb)
111*4882a593Smuzhiyun addr_mode |= ST7735R_RGB;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
114*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
115*4882a593Smuzhiyun MIPI_DCS_PIXEL_FMT_16BIT);
116*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_GAMCTRP1, 0x02, 0x1c, 0x07, 0x12, 0x37,
117*4882a593Smuzhiyun 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2b, 0x39, 0x00, 0x01,
118*4882a593Smuzhiyun 0x03, 0x10);
119*4882a593Smuzhiyun mipi_dbi_command(dbi, ST7735R_GAMCTRN1, 0x03, 0x1d, 0x07, 0x06, 0x2e,
120*4882a593Smuzhiyun 0x2c, 0x29, 0x2d, 0x2e, 0x2e, 0x37, 0x3f, 0x00, 0x00,
121*4882a593Smuzhiyun 0x02, 0x10);
122*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun msleep(100);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun mipi_dbi_command(dbi, MIPI_DCS_ENTER_NORMAL_MODE);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun msleep(20);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
131*4882a593Smuzhiyun out_exit:
132*4882a593Smuzhiyun drm_dev_exit(idx);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = {
136*4882a593Smuzhiyun .enable = st7735r_pipe_enable,
137*4882a593Smuzhiyun .disable = mipi_dbi_pipe_disable,
138*4882a593Smuzhiyun .update = mipi_dbi_pipe_update,
139*4882a593Smuzhiyun .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun static const struct st7735r_cfg jd_t18003_t01_cfg = {
143*4882a593Smuzhiyun .mode = { DRM_SIMPLE_MODE(128, 160, 28, 35) },
144*4882a593Smuzhiyun /* Cannot read from Adafruit 1.8" display via SPI */
145*4882a593Smuzhiyun .write_only = true,
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun static const struct st7735r_cfg rh128128t_cfg = {
149*4882a593Smuzhiyun .mode = { DRM_SIMPLE_MODE(128, 128, 25, 26) },
150*4882a593Smuzhiyun .left_offset = 2,
151*4882a593Smuzhiyun .top_offset = 3,
152*4882a593Smuzhiyun .rgb = true,
153*4882a593Smuzhiyun };
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun static struct drm_driver st7735r_driver = {
158*4882a593Smuzhiyun .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
159*4882a593Smuzhiyun .fops = &st7735r_fops,
160*4882a593Smuzhiyun DRM_GEM_CMA_DRIVER_OPS_VMAP,
161*4882a593Smuzhiyun .debugfs_init = mipi_dbi_debugfs_init,
162*4882a593Smuzhiyun .name = "st7735r",
163*4882a593Smuzhiyun .desc = "Sitronix ST7735R",
164*4882a593Smuzhiyun .date = "20171128",
165*4882a593Smuzhiyun .major = 1,
166*4882a593Smuzhiyun .minor = 0,
167*4882a593Smuzhiyun };
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun static const struct of_device_id st7735r_of_match[] = {
170*4882a593Smuzhiyun { .compatible = "jianda,jd-t18003-t01", .data = &jd_t18003_t01_cfg },
171*4882a593Smuzhiyun { .compatible = "okaya,rh128128t", .data = &rh128128t_cfg },
172*4882a593Smuzhiyun { },
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, st7735r_of_match);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun static const struct spi_device_id st7735r_id[] = {
177*4882a593Smuzhiyun { "jd-t18003-t01", (uintptr_t)&jd_t18003_t01_cfg },
178*4882a593Smuzhiyun { "rh128128t", (uintptr_t)&rh128128t_cfg },
179*4882a593Smuzhiyun { },
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun MODULE_DEVICE_TABLE(spi, st7735r_id);
182*4882a593Smuzhiyun
st7735r_probe(struct spi_device * spi)183*4882a593Smuzhiyun static int st7735r_probe(struct spi_device *spi)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct device *dev = &spi->dev;
186*4882a593Smuzhiyun const struct st7735r_cfg *cfg;
187*4882a593Smuzhiyun struct mipi_dbi_dev *dbidev;
188*4882a593Smuzhiyun struct st7735r_priv *priv;
189*4882a593Smuzhiyun struct drm_device *drm;
190*4882a593Smuzhiyun struct mipi_dbi *dbi;
191*4882a593Smuzhiyun struct gpio_desc *dc;
192*4882a593Smuzhiyun u32 rotation = 0;
193*4882a593Smuzhiyun int ret;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun cfg = device_get_match_data(&spi->dev);
196*4882a593Smuzhiyun if (!cfg)
197*4882a593Smuzhiyun cfg = (void *)spi_get_device_id(spi)->driver_data;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun priv = devm_drm_dev_alloc(dev, &st7735r_driver,
200*4882a593Smuzhiyun struct st7735r_priv, dbidev.drm);
201*4882a593Smuzhiyun if (IS_ERR(priv))
202*4882a593Smuzhiyun return PTR_ERR(priv);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun dbidev = &priv->dbidev;
205*4882a593Smuzhiyun priv->cfg = cfg;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun dbi = &dbidev->dbi;
208*4882a593Smuzhiyun drm = &dbidev->drm;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
211*4882a593Smuzhiyun if (IS_ERR(dbi->reset)) {
212*4882a593Smuzhiyun DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
213*4882a593Smuzhiyun return PTR_ERR(dbi->reset);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
217*4882a593Smuzhiyun if (IS_ERR(dc)) {
218*4882a593Smuzhiyun DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
219*4882a593Smuzhiyun return PTR_ERR(dc);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun dbidev->backlight = devm_of_find_backlight(dev);
223*4882a593Smuzhiyun if (IS_ERR(dbidev->backlight))
224*4882a593Smuzhiyun return PTR_ERR(dbidev->backlight);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun device_property_read_u32(dev, "rotation", &rotation);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun ret = mipi_dbi_spi_init(spi, dbi, dc);
229*4882a593Smuzhiyun if (ret)
230*4882a593Smuzhiyun return ret;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun if (cfg->write_only)
233*4882a593Smuzhiyun dbi->read_commands = NULL;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun dbidev->left_offset = cfg->left_offset;
236*4882a593Smuzhiyun dbidev->top_offset = cfg->top_offset;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun ret = mipi_dbi_dev_init(dbidev, &st7735r_pipe_funcs, &cfg->mode,
239*4882a593Smuzhiyun rotation);
240*4882a593Smuzhiyun if (ret)
241*4882a593Smuzhiyun return ret;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun drm_mode_config_reset(drm);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun ret = drm_dev_register(drm, 0);
246*4882a593Smuzhiyun if (ret)
247*4882a593Smuzhiyun return ret;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun spi_set_drvdata(spi, drm);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun drm_fbdev_generic_setup(drm, 0);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
st7735r_remove(struct spi_device * spi)256*4882a593Smuzhiyun static int st7735r_remove(struct spi_device *spi)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun struct drm_device *drm = spi_get_drvdata(spi);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun drm_dev_unplug(drm);
261*4882a593Smuzhiyun drm_atomic_helper_shutdown(drm);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return 0;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
st7735r_shutdown(struct spi_device * spi)266*4882a593Smuzhiyun static void st7735r_shutdown(struct spi_device *spi)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun drm_atomic_helper_shutdown(spi_get_drvdata(spi));
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun static struct spi_driver st7735r_spi_driver = {
272*4882a593Smuzhiyun .driver = {
273*4882a593Smuzhiyun .name = "st7735r",
274*4882a593Smuzhiyun .of_match_table = st7735r_of_match,
275*4882a593Smuzhiyun },
276*4882a593Smuzhiyun .id_table = st7735r_id,
277*4882a593Smuzhiyun .probe = st7735r_probe,
278*4882a593Smuzhiyun .remove = st7735r_remove,
279*4882a593Smuzhiyun .shutdown = st7735r_shutdown,
280*4882a593Smuzhiyun };
281*4882a593Smuzhiyun module_spi_driver(st7735r_spi_driver);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun MODULE_DESCRIPTION("Sitronix ST7735R DRM driver");
284*4882a593Smuzhiyun MODULE_AUTHOR("David Lechner <david@lechnology.com>");
285*4882a593Smuzhiyun MODULE_LICENSE("GPL");
286