• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws abstract display implementation for ili9341 on spi
3  *
4  * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include <private-lib-core.h>
26 #include <drivers/devices/display/ili9341.h>
27 
28 
29 static uint8_t ili9341_320x240_init[] = {
30 	/*
31 	 * This provides 70Hz 320x240 at RGB565, we assume im[3:0] is 1110
32 	 * which is 4-bit SPI
33 	 */
34 
35 	 3, ILI9341_FACPWCTRB,	    0x00, 0x83, 0x30,
36 	 4, ILI9341_FACDRTIMCTRA,   0x64, 0x03, 0x12, 0x81,
37 	 3, ILI9341_FACPWCTRA,	    0x85, 0x01, 0x79,
38 	 5, ILI9341_FACPUMPRAT,	    0x39, 0x2c, 0x00, 0x34, 0x02,
39 	 1, ILI9341_FACDRTIMCTR,    0x20,
40 	 2, ILI9341_FACPWCTR1,	    0x00, 0x00,
41 
42 	 1, ILI9341_PWCTR1,	    0x26,
43 	 1, ILI9341_PWCTR2,	    0x11,
44 	 2, ILI9341_VMCTR1,	    0x35, 0x3e,
45 	 1, ILI9341_VMCTR2,	    0xbe,
46 	 1, ILI9341_MADCTL,	    0x28,
47 	 1, ILI9341_VSCRSADD,	    0x00,
48 	 1, ILI9341_PIXFMT,	    0x55,
49 	 2, ILI9341_FRMCTR1,	    0x00, 0x1b,
50 	 1, ILI9341_FACSETGAMMACRV, 0x00,
51 	 1, ILI9341_GAMMASET,	    0x01,
52 	15, ILI9341_GMCTRP1,	    0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e,
53 				    0xf1, 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09,
54 				    0x00,
55 	15, ILI9341_GMCTRN1,	    0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31,
56 				    0xc1, 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36,
57 				    0x0f,
58 	4, ILI9341_DFUNCTR,	    0x0a, 0x82, 0x27, 0x00,
59 };
60 
61 int
lws_display_ili9341_spi_init(const struct lws_display * disp)62 lws_display_ili9341_spi_init(const struct lws_display *disp)
63 {
64 	const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
65 	lws_spi_desc_t desc;
66 	size_t pos = 0;
67 	uint8_t u[8];
68 
69 	lwsl_user("%s\n", __func__);
70 
71 	/* hardware nRESET */
72 
73 	if (ili->gpio) {
74 		ili->gpio->mode(ili->reset_gpio, LWSGGPIO_FL_WRITE |
75 					         LWSGGPIO_FL_PULLUP);
76 		ili->gpio->set(ili->reset_gpio, 0);
77 
78 		lws_msleep(1);
79 		ili->gpio->set(ili->reset_gpio, 1);
80 		lws_msleep(1);
81 	}
82 
83 	/*
84 	 * We cut the init table up into transactions... atm we just go with
85 	 * the fact that bb spi is synchronous, using async / dma we can't use
86 	 * a single desc on the stack like this
87 	 */
88 
89 	memset(&desc, 0, sizeof(desc));
90 	desc.count_cmd = 1;
91 
92 	while (pos < LWS_ARRAY_SIZE(ili9341_320x240_init)) {
93 		desc.count_write = ili9341_320x240_init[pos++];
94 		desc.src = &ili9341_320x240_init[pos++];
95 		desc.data = &ili9341_320x240_init[pos];
96 		pos += desc.count_write;
97 
98 		ili->spi->queue(ili->spi, &desc);
99 	}
100 
101 	u[0] = ILI9341_SLPOUT;
102 	desc.src = &u[0];
103 	desc.count_write = 0;
104 	ili->spi->queue(ili->spi, &desc);
105 
106 	lws_msleep(5);
107 
108 	u[0] = ILI9341_DISPON;
109 	ili->spi->queue(ili->spi, &desc);
110 
111 	return 0;
112 }
113 
114 /* backlight handled by PWM */
115 
116 int
lws_display_ili9341_spi_brightness(const struct lws_display * disp,uint8_t b)117 lws_display_ili9341_spi_brightness(const struct lws_display *disp, uint8_t b)
118 {
119 	return 0;
120 }
121 
122 int
lws_display_ili9341_spi_blit(const struct lws_display * disp,const uint8_t * src,lws_display_scalar x,lws_display_scalar y,lws_display_scalar w,lws_display_scalar h)123 lws_display_ili9341_spi_blit(const struct lws_display *disp, const uint8_t *src,
124 			     lws_display_scalar x, lws_display_scalar y,
125 			     lws_display_scalar w, lws_display_scalar h)
126 {
127 	const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
128 	lws_spi_desc_t desc;
129 	uint8_t u[5];
130 
131 	memset(&desc, 0, sizeof(desc));
132 	desc.count_cmd = 1;
133 	desc.src = &u[0];
134 	desc.count_write = 0;
135 
136 	/*
137 	 * Blit a line at a time
138 	 */
139 
140 	while (h--) {
141 
142 		u[0] = ILI9341_CASET;
143 		desc.data = &u[1];
144 		u[1] = x;
145 		u[2] = x;
146 		u[3] = w >> 8;
147 		u[4] = w & 0xff;
148 		desc.count_write = 4;
149 		ili->spi->queue(ili->spi, &desc);
150 
151 		u[0] = ILI9341_PASET;
152 		u[1] = y >> 8;
153 		u[2] = y & 0xff;
154 		u[3] = (y + 1) >> 8;
155 		u[4] = (y + 1) & 0xff;
156 		desc.count_write = 4;
157 		ili->spi->queue(ili->spi, &desc);
158 
159 		u[0] = ILI9341_RAMWR;
160 		desc.data = src;
161 		desc.count_write = w * 2;
162 		ili->spi->queue(ili->spi, &desc);
163 		src += w * 2;
164 		y++;
165 	}
166 
167 	return 0;
168 }
169 
170 int
lws_display_ili9341_spi_power(const struct lws_display * disp,int state)171 lws_display_ili9341_spi_power(const struct lws_display *disp, int state)
172 {
173 
174 	const lws_display_ili9341_t *ili = (const lws_display_ili9341_t *)disp;
175 	lws_spi_desc_t desc;
176 	uint8_t u[1];
177 
178 	memset(&desc, 0, sizeof(desc));
179 	desc.count_cmd = 1;
180 	desc.data = desc.src = &u[0];
181 	u[0] = state ? ILI9341_SLPOUT : ILI9341_SLPIN;
182 	ili->spi->queue(ili->spi, &desc);
183 
184 	/* we're not going to do anything useful for 5ms after this */
185 
186 	return 0;
187 }
188