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