1 /*
2 * Copyright (c) 2020 PHYTEC Messtechnik GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT gooddisplay_gd7965
8
9 #include <string.h>
10 #include <device.h>
11 #include <init.h>
12 #include <drivers/display.h>
13 #include <drivers/gpio.h>
14 #include <drivers/spi.h>
15 #include <sys/byteorder.h>
16
17 #include "gd7965_regs.h"
18
19 #include <logging/log.h>
20 LOG_MODULE_REGISTER(gd7965, CONFIG_DISPLAY_LOG_LEVEL);
21
22 /**
23 * GD7965 compatible EPD controller driver.
24 *
25 * Currently only the black/white pannels are supported (KW mode),
26 * also first gate/source should be 0.
27 */
28
29 #define GD7965_DC_PIN DT_INST_GPIO_PIN(0, dc_gpios)
30 #define GD7965_DC_FLAGS DT_INST_GPIO_FLAGS(0, dc_gpios)
31 #define GD7965_DC_CNTRL DT_INST_GPIO_LABEL(0, dc_gpios)
32 #define GD7965_BUSY_PIN DT_INST_GPIO_PIN(0, busy_gpios)
33 #define GD7965_BUSY_CNTRL DT_INST_GPIO_LABEL(0, busy_gpios)
34 #define GD7965_BUSY_FLAGS DT_INST_GPIO_FLAGS(0, busy_gpios)
35 #define GD7965_RESET_PIN DT_INST_GPIO_PIN(0, reset_gpios)
36 #define GD7965_RESET_CNTRL DT_INST_GPIO_LABEL(0, reset_gpios)
37 #define GD7965_RESET_FLAGS DT_INST_GPIO_FLAGS(0, reset_gpios)
38
39 #define EPD_PANEL_WIDTH DT_INST_PROP(0, width)
40 #define EPD_PANEL_HEIGHT DT_INST_PROP(0, height)
41 #define GD7965_PIXELS_PER_BYTE 8U
42
43 /* Horizontally aligned page! */
44 #define GD7965_NUMOF_PAGES (EPD_PANEL_WIDTH / \
45 GD7965_PIXELS_PER_BYTE)
46 #define GD7965_PANEL_FIRST_GATE 0U
47 #define GD7965_PANEL_LAST_GATE (EPD_PANEL_HEIGHT - 1)
48 #define GD7965_PANEL_FIRST_PAGE 0U
49 #define GD7965_PANEL_LAST_PAGE (GD7965_NUMOF_PAGES - 1)
50
51
52 struct gd7965_data {
53 const struct gd7965_config *config;
54 const struct device *reset;
55 const struct device *dc;
56 const struct device *busy;
57 };
58
59 struct gd7965_config {
60 struct spi_dt_spec bus;
61 };
62
63 static uint8_t gd7965_softstart[] = DT_INST_PROP(0, softstart);
64 static uint8_t gd7965_pwr[] = DT_INST_PROP(0, pwr);
65
66 /* Border and data polarity settings */
67 static uint8_t bdd_polarity;
68
69 static bool blanking_on = true;
70
gd7965_write_cmd(struct gd7965_data * driver,uint8_t cmd,uint8_t * data,size_t len)71 static inline int gd7965_write_cmd(struct gd7965_data *driver,
72 uint8_t cmd, uint8_t *data, size_t len)
73 {
74 struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)};
75 struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
76
77 gpio_pin_set(driver->dc, GD7965_DC_PIN, 1);
78 if (spi_write_dt(&driver->config->bus, &buf_set)) {
79 return -EIO;
80 }
81
82 if (data != NULL) {
83 buf.buf = data;
84 buf.len = len;
85 gpio_pin_set(driver->dc, GD7965_DC_PIN, 0);
86 if (spi_write_dt(&driver->config->bus, &buf_set)) {
87 return -EIO;
88 }
89 }
90
91 return 0;
92 }
93
gd7965_busy_wait(struct gd7965_data * driver)94 static inline void gd7965_busy_wait(struct gd7965_data *driver)
95 {
96 int pin = gpio_pin_get(driver->busy, GD7965_BUSY_PIN);
97
98 while (pin > 0) {
99 __ASSERT(pin >= 0, "Failed to get pin level");
100 LOG_DBG("wait %u", pin);
101 k_sleep(K_MSEC(GD7965_BUSY_DELAY));
102 pin = gpio_pin_get(driver->busy, GD7965_BUSY_PIN);
103 }
104 }
105
gd7965_update_display(const struct device * dev)106 static int gd7965_update_display(const struct device *dev)
107 {
108 struct gd7965_data *driver = dev->data;
109
110 LOG_DBG("Trigger update sequence");
111 if (gd7965_write_cmd(driver, GD7965_CMD_DRF, NULL, 0)) {
112 return -EIO;
113 }
114
115 k_sleep(K_MSEC(GD7965_BUSY_DELAY));
116
117 return 0;
118 }
119
gd7965_blanking_off(const struct device * dev)120 static int gd7965_blanking_off(const struct device *dev)
121 {
122 struct gd7965_data *driver = dev->data;
123
124 if (blanking_on) {
125 /* Update EPD pannel in normal mode */
126 gd7965_busy_wait(driver);
127 if (gd7965_update_display(dev)) {
128 return -EIO;
129 }
130 }
131
132 blanking_on = false;
133
134 return 0;
135 }
136
gd7965_blanking_on(const struct device * dev)137 static int gd7965_blanking_on(const struct device *dev)
138 {
139 blanking_on = true;
140
141 return 0;
142 }
143
gd7965_write(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,const void * buf)144 static int gd7965_write(const struct device *dev, const uint16_t x, const uint16_t y,
145 const struct display_buffer_descriptor *desc,
146 const void *buf)
147 {
148 struct gd7965_data *driver = dev->data;
149 uint16_t x_end_idx = x + desc->width - 1;
150 uint16_t y_end_idx = y + desc->height - 1;
151 uint8_t ptl[GD7965_PTL_REG_LENGTH] = {0};
152 size_t buf_len;
153
154 LOG_DBG("x %u, y %u, height %u, width %u, pitch %u",
155 x, y, desc->height, desc->width, desc->pitch);
156
157 buf_len = MIN(desc->buf_size,
158 desc->height * desc->width / GD7965_PIXELS_PER_BYTE);
159 __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width");
160 __ASSERT(buf != NULL, "Buffer is not available");
161 __ASSERT(buf_len != 0U, "Buffer of length zero");
162 __ASSERT(!(desc->width % GD7965_PIXELS_PER_BYTE),
163 "Buffer width not multiple of %d", GD7965_PIXELS_PER_BYTE);
164
165 if ((y_end_idx > (EPD_PANEL_HEIGHT - 1)) ||
166 (x_end_idx > (EPD_PANEL_WIDTH - 1))) {
167 LOG_ERR("Position out of bounds");
168 return -EINVAL;
169 }
170
171 /* Setup Partial Window and enable Partial Mode */
172 sys_put_be16(x, &ptl[GD7965_PTL_HRST_IDX]);
173 sys_put_be16(x_end_idx, &ptl[GD7965_PTL_HRED_IDX]);
174 sys_put_be16(y, &ptl[GD7965_PTL_VRST_IDX]);
175 sys_put_be16(y_end_idx, &ptl[GD7965_PTL_VRED_IDX]);
176 ptl[sizeof(ptl) - 1] = GD7965_PTL_PT_SCAN;
177 LOG_HEXDUMP_DBG(ptl, sizeof(ptl), "ptl");
178
179 gd7965_busy_wait(driver);
180 if (gd7965_write_cmd(driver, GD7965_CMD_PTIN, NULL, 0)) {
181 return -EIO;
182 }
183
184 if (gd7965_write_cmd(driver, GD7965_CMD_PTL, ptl, sizeof(ptl))) {
185 return -EIO;
186 }
187
188 /* Disable boarder output */
189 bdd_polarity |= GD7965_CDI_BDZ;
190 if (gd7965_write_cmd(driver, GD7965_CMD_CDI,
191 &bdd_polarity, sizeof(bdd_polarity))) {
192 return -EIO;
193 }
194
195 if (gd7965_write_cmd(driver, GD7965_CMD_DTM2, (uint8_t *)buf, buf_len)) {
196 return -EIO;
197 }
198
199 /* Update partial window and disable Partial Mode */
200 if (blanking_on == false) {
201 if (gd7965_update_display(dev)) {
202 return -EIO;
203 }
204 }
205
206 /* Enable boarder output */
207 bdd_polarity &= ~GD7965_CDI_BDZ;
208 if (gd7965_write_cmd(driver, GD7965_CMD_CDI,
209 &bdd_polarity, sizeof(bdd_polarity))) {
210 return -EIO;
211 }
212
213 if (gd7965_write_cmd(driver, GD7965_CMD_PTOUT, NULL, 0)) {
214 return -EIO;
215 }
216
217 return 0;
218 }
219
gd7965_read(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,void * buf)220 static int gd7965_read(const struct device *dev, const uint16_t x, const uint16_t y,
221 const struct display_buffer_descriptor *desc, void *buf)
222 {
223 LOG_ERR("not supported");
224 return -ENOTSUP;
225 }
226
gd7965_get_framebuffer(const struct device * dev)227 static void *gd7965_get_framebuffer(const struct device *dev)
228 {
229 LOG_ERR("not supported");
230 return NULL;
231 }
232
gd7965_set_brightness(const struct device * dev,const uint8_t brightness)233 static int gd7965_set_brightness(const struct device *dev,
234 const uint8_t brightness)
235 {
236 LOG_WRN("not supported");
237 return -ENOTSUP;
238 }
239
gd7965_set_contrast(const struct device * dev,uint8_t contrast)240 static int gd7965_set_contrast(const struct device *dev, uint8_t contrast)
241 {
242 LOG_WRN("not supported");
243 return -ENOTSUP;
244 }
245
gd7965_get_capabilities(const struct device * dev,struct display_capabilities * caps)246 static void gd7965_get_capabilities(const struct device *dev,
247 struct display_capabilities *caps)
248 {
249 memset(caps, 0, sizeof(struct display_capabilities));
250 caps->x_resolution = EPD_PANEL_WIDTH;
251 caps->y_resolution = EPD_PANEL_HEIGHT;
252 caps->supported_pixel_formats = PIXEL_FORMAT_MONO10;
253 caps->current_pixel_format = PIXEL_FORMAT_MONO10;
254 caps->screen_info = SCREEN_INFO_MONO_MSB_FIRST | SCREEN_INFO_EPD;
255 }
256
gd7965_set_orientation(const struct device * dev,const enum display_orientation orientation)257 static int gd7965_set_orientation(const struct device *dev,
258 const enum display_orientation
259 orientation)
260 {
261 LOG_ERR("Unsupported");
262 return -ENOTSUP;
263 }
264
gd7965_set_pixel_format(const struct device * dev,const enum display_pixel_format pf)265 static int gd7965_set_pixel_format(const struct device *dev,
266 const enum display_pixel_format pf)
267 {
268 if (pf == PIXEL_FORMAT_MONO10) {
269 return 0;
270 }
271
272 LOG_ERR("not supported");
273 return -ENOTSUP;
274 }
275
gd7965_clear_and_write_buffer(const struct device * dev,uint8_t pattern,bool update)276 static int gd7965_clear_and_write_buffer(const struct device *dev,
277 uint8_t pattern, bool update)
278 {
279 struct display_buffer_descriptor desc = {
280 .buf_size = GD7965_NUMOF_PAGES,
281 .width = EPD_PANEL_WIDTH,
282 .height = 1,
283 .pitch = EPD_PANEL_WIDTH,
284 };
285 uint8_t *line;
286
287 line = k_malloc(GD7965_NUMOF_PAGES);
288 if (line == NULL) {
289 return -ENOMEM;
290 }
291
292 memset(line, pattern, GD7965_NUMOF_PAGES);
293 for (int i = 0; i < EPD_PANEL_HEIGHT; i++) {
294 gd7965_write(dev, 0, i, &desc, line);
295 }
296
297 k_free(line);
298
299 if (update == true) {
300 if (gd7965_update_display(dev)) {
301 return -EIO;
302 }
303 }
304
305 return 0;
306 }
307
gd7965_controller_init(const struct device * dev)308 static int gd7965_controller_init(const struct device *dev)
309 {
310 struct gd7965_data *driver = dev->data;
311 uint8_t tmp[GD7965_TRES_REG_LENGTH];
312
313 gpio_pin_set(driver->reset, GD7965_RESET_PIN, 1);
314 k_sleep(K_MSEC(GD7965_RESET_DELAY));
315 gpio_pin_set(driver->reset, GD7965_RESET_PIN, 0);
316 k_sleep(K_MSEC(GD7965_RESET_DELAY));
317 gd7965_busy_wait(driver);
318
319 LOG_DBG("Initialize GD7965 controller");
320
321 if (gd7965_write_cmd(driver, GD7965_CMD_PWR, gd7965_pwr,
322 sizeof(gd7965_pwr))) {
323 return -EIO;
324 }
325
326 if (gd7965_write_cmd(driver, GD7965_CMD_BTST,
327 gd7965_softstart, sizeof(gd7965_softstart))) {
328 return -EIO;
329 }
330
331 /* Turn on: booster, controller, regulators, and sensor. */
332 if (gd7965_write_cmd(driver, GD7965_CMD_PON, NULL, 0)) {
333 return -EIO;
334 }
335
336 k_sleep(K_MSEC(GD7965_PON_DELAY));
337 gd7965_busy_wait(driver);
338
339 /* Pannel settings, KW mode */
340 tmp[0] = GD7965_PSR_KW_R |
341 GD7965_PSR_UD |
342 GD7965_PSR_SHL |
343 GD7965_PSR_SHD |
344 GD7965_PSR_RST;
345 if (gd7965_write_cmd(driver, GD7965_CMD_PSR, tmp, 1)) {
346 return -EIO;
347 }
348
349 /* Set panel resolution */
350 sys_put_be16(EPD_PANEL_WIDTH, &tmp[GD7965_TRES_HRES_IDX]);
351 sys_put_be16(EPD_PANEL_HEIGHT, &tmp[GD7965_TRES_VRES_IDX]);
352 LOG_HEXDUMP_DBG(tmp, sizeof(tmp), "TRES");
353 if (gd7965_write_cmd(driver, GD7965_CMD_TRES,
354 tmp, GD7965_TRES_REG_LENGTH)) {
355 return -EIO;
356 }
357
358 bdd_polarity = GD7965_CDI_BDV1 |
359 GD7965_CDI_N2OCP | GD7965_CDI_DDX0;
360 tmp[GD7965_CDI_BDZ_DDX_IDX] = bdd_polarity;
361 tmp[GD7965_CDI_CDI_IDX] = DT_INST_PROP(0, cdi);
362 LOG_HEXDUMP_DBG(tmp, GD7965_CDI_REG_LENGTH, "CDI");
363 if (gd7965_write_cmd(driver, GD7965_CMD_CDI, tmp,
364 GD7965_CDI_REG_LENGTH)) {
365 return -EIO;
366 }
367
368 tmp[0] = DT_INST_PROP(0, tcon);
369 if (gd7965_write_cmd(driver, GD7965_CMD_TCON, tmp, 1)) {
370 return -EIO;
371 }
372
373 /* Enable Auto Sequence */
374 tmp[0] = GD7965_AUTO_PON_DRF_POF;
375 if (gd7965_write_cmd(driver, GD7965_CMD_AUTO, tmp, 1)) {
376 return -EIO;
377 }
378
379 if (gd7965_clear_and_write_buffer(dev, 0xff, false)) {
380 return -1;
381 }
382
383 return 0;
384 }
385
gd7965_init(const struct device * dev)386 static int gd7965_init(const struct device *dev)
387 {
388 const struct gd7965_config *config = dev->config;
389 struct gd7965_data *driver = dev->data;
390
391 LOG_DBG("");
392
393 if (!spi_is_ready(&config->bus)) {
394 LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
395 return -ENODEV;
396 }
397
398 driver->reset = device_get_binding(GD7965_RESET_CNTRL);
399 if (driver->reset == NULL) {
400 LOG_ERR("Could not get GPIO port for GD7965 reset");
401 return -EIO;
402 }
403
404 gpio_pin_configure(driver->reset, GD7965_RESET_PIN,
405 GPIO_OUTPUT_INACTIVE | GD7965_RESET_FLAGS);
406
407 driver->dc = device_get_binding(GD7965_DC_CNTRL);
408 if (driver->dc == NULL) {
409 LOG_ERR("Could not get GPIO port for GD7965 DC signal");
410 return -EIO;
411 }
412
413 gpio_pin_configure(driver->dc, GD7965_DC_PIN,
414 GPIO_OUTPUT_INACTIVE | GD7965_DC_FLAGS);
415
416 driver->busy = device_get_binding(GD7965_BUSY_CNTRL);
417 if (driver->busy == NULL) {
418 LOG_ERR("Could not get GPIO port for GD7965 busy signal");
419 return -EIO;
420 }
421
422 gpio_pin_configure(driver->busy, GD7965_BUSY_PIN,
423 GPIO_INPUT | GD7965_BUSY_FLAGS);
424
425 return gd7965_controller_init(dev);
426 }
427
428 static struct gd7965_data gd7965_driver = {
429 .config = &gd7965_config
430 };
431
432 static const struct gd7965_config gd7965_config {
433 .bus = SPI_DT_SPEC_INST_GET(
434 0, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0)
435 };
436
437 static struct display_driver_api gd7965_driver_api = {
438 .blanking_on = gd7965_blanking_on,
439 .blanking_off = gd7965_blanking_off,
440 .write = gd7965_write,
441 .read = gd7965_read,
442 .get_framebuffer = gd7965_get_framebuffer,
443 .set_brightness = gd7965_set_brightness,
444 .set_contrast = gd7965_set_contrast,
445 .get_capabilities = gd7965_get_capabilities,
446 .set_pixel_format = gd7965_set_pixel_format,
447 .set_orientation = gd7965_set_orientation,
448 };
449
450
451 DEVICE_DT_INST_DEFINE(0, gd7965_init, NULL,
452 &gd7965_driver, &gd7965_config,
453 POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY,
454 &gd7965_driver_api);
455