1 /**
2  * Copyright (c) 2023 Mr Beam Lasers GmbH.
3  * Copyright (c) 2023 Amrith Venkat Kesavamoorthi <amrith@mr-beam.org>
4  * Copyright (c) 2023 Martin Kiepfer <mrmarteng@teleschirm.org>
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #define DT_DRV_COMPAT galaxycore_gc9x01x
8 
9 #include "display_gc9x01x.h"
10 
11 #include <zephyr/dt-bindings/display/panel.h>
12 #include <zephyr/drivers/display.h>
13 #include <zephyr/drivers/mipi_dbi.h>
14 #include <zephyr/pm/device.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/sys/byteorder.h>
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(display_gc9x01x, CONFIG_DISPLAY_LOG_LEVEL);
20 
21 /* Maximum number of default init registers  */
22 #define GC9X01X_NUM_DEFAULT_INIT_REGS 12U
23 
24 /* Display data struct */
25 struct gc9x01x_data {
26 	uint8_t bytes_per_pixel;
27 	enum display_pixel_format pixel_format;
28 	enum display_orientation orientation;
29 };
30 
31 /* Configuration data struct.*/
32 struct gc9x01x_config {
33 	const struct device *mipi_dev;
34 	struct mipi_dbi_config dbi_config;
35 	uint8_t pixel_format;
36 	uint16_t orientation;
37 	uint16_t x_resolution;
38 	uint16_t y_resolution;
39 	bool inversion;
40 	const void *regs;
41 };
42 
43 /* Initialization command data struct  */
44 struct gc9x01x_default_init_regs {
45 	uint8_t cmd;
46 	uint8_t len;
47 	uint8_t data[GC9X01X_NUM_DEFAULT_INIT_REGS];
48 };
49 
50 /*
51  * Default initialization commands. There are a lot of undocumented commands
52  * within the manufacturer sample code, that are essential for proper operation of
53  * the display controller
54  */
55 static const struct gc9x01x_default_init_regs default_init_regs[] = {
56 	{
57 		.cmd = 0xEBU,
58 		.len = 1U,
59 		.data = {0x14U},
60 	},
61 	{
62 		.cmd = 0x84U,
63 		.len = 1U,
64 		.data = {0x40U},
65 	},
66 	{
67 		.cmd = 0x85U,
68 		.len = 1U,
69 		.data = {0xFFU},
70 	},
71 	{
72 		.cmd = 0x86U,
73 		.len = 1U,
74 		.data = {0xFFU},
75 	},
76 	{
77 		.cmd = 0x87U,
78 		.len = 1U,
79 		.data = {0xFFU},
80 	},
81 	{
82 		.cmd = 0x88U,
83 		.len = 1U,
84 		.data = {0x0AU},
85 	},
86 	{
87 		.cmd = 0x89U,
88 		.len = 1U,
89 		.data = {0x21U},
90 	},
91 	{
92 		.cmd = 0x8AU,
93 		.len = 1U,
94 		.data = {0x00U},
95 	},
96 	{
97 		.cmd = 0x8BU,
98 		.len = 1U,
99 		.data = {0x80U},
100 	},
101 	{
102 		.cmd = 0x8CU,
103 		.len = 1U,
104 		.data = {0x01U},
105 	},
106 	{
107 		.cmd = 0x8DU,
108 		.len = 1U,
109 		.data = {0x01U},
110 	},
111 	{
112 		.cmd = 0x8EU,
113 		.len = 1U,
114 		.data = {0xFFU},
115 	},
116 	{
117 		.cmd = 0x8FU,
118 		.len = 1U,
119 		.data = {0xFFU},
120 	},
121 	{
122 		.cmd = 0xB6U,
123 		.len = 2U,
124 		.data = {0x00U, 0x20U},
125 	},
126 	{
127 		.cmd = 0x90U,
128 		.len = 4U,
129 		.data = {0x08U, 0x08U, 0x08U, 0x08U},
130 	},
131 	{
132 		.cmd = 0xBDU,
133 		.len = 1U,
134 		.data = {0x06U},
135 	},
136 	{
137 		.cmd = 0xBCU,
138 		.len = 1U,
139 		.data = {0x00U},
140 	},
141 	{
142 		.cmd = 0xFFU,
143 		.len = 3U,
144 		.data = {0x60U, 0x01U, 0x04U},
145 	},
146 	{
147 		.cmd = 0xBEU,
148 		.len = 1U,
149 		.data = {0x11U},
150 	},
151 	{
152 		.cmd = 0xE1U,
153 		.len = 2U,
154 		.data = {0x10U, 0x0EU},
155 	},
156 	{
157 		.cmd = 0xDFU,
158 		.len = 3U,
159 		.data = {0x21U, 0x0CU, 0x02U},
160 	},
161 	{
162 		.cmd = 0xEDU,
163 		.len = 2U,
164 		.data = {0x1BU, 0x0BU},
165 	},
166 	{
167 		.cmd = 0xAEU,
168 		.len = 1U,
169 		.data = {0x77U},
170 	},
171 	{
172 		.cmd = 0xCDU,
173 		.len = 1U,
174 		.data = {0x63U},
175 	},
176 	{
177 		.cmd = 0x70U,
178 		.len = 9U,
179 		.data = {0x07U, 0x07U, 0x04U, 0x0EU, 0x0FU, 0x09U, 0x07U, 0x08U, 0x03U},
180 	},
181 	{
182 		.cmd = 0x62U,
183 		.len = 12U,
184 		.data = {0x18U, 0x0DU, 0x71U, 0xEDU, 0x70U, 0x70U, 0x18U, 0x0FU, 0x71U, 0xEFU,
185 			 0x70U, 0x70U},
186 	},
187 	{
188 		.cmd = 0x63U,
189 		.len = 12U,
190 		.data = {0x18U, 0x11U, 0x71U, 0xF1U, 0x70U, 0x70U, 0x18U, 0x13U, 0x71U, 0xF3U,
191 			 0x70U, 0x70U},
192 	},
193 	{
194 		.cmd = 0x64U,
195 		.len = 7U,
196 		.data = {0x28U, 0x29U, 0xF1U, 0x01U, 0xF1U, 0x00U, 0x07U},
197 	},
198 	{
199 		.cmd = 0x66U,
200 		.len = 10U,
201 		.data = {0x3CU, 0x00U, 0xCDU, 0x67U, 0x45U, 0x45U, 0x10U, 0x00U, 0x00U, 0x00U},
202 	},
203 	{
204 		.cmd = 0x67U,
205 		.len = 10U,
206 		.data = {0x00U, 0x3CU, 0x00U, 0x00U, 0x00U, 0x01U, 0x54U, 0x10U, 0x32U, 0x98U},
207 	},
208 	{
209 		.cmd = 0x74U,
210 		.len = 7U,
211 		.data = {0x10U, 0x85U, 0x80U, 0x00U, 0x00U, 0x4EU, 0x00U},
212 	},
213 	{
214 		.cmd = 0x98U,
215 		.len = 2U,
216 		.data = {0x3EU, 0x07U},
217 	},
218 };
219 
gc9x01x_transmit(const struct device * dev,uint8_t cmd,const void * tx_data,size_t tx_len)220 static int gc9x01x_transmit(const struct device *dev, uint8_t cmd, const void *tx_data,
221 			    size_t tx_len)
222 {
223 	const struct gc9x01x_config *config = dev->config;
224 
225 	return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config,
226 				      cmd, tx_data, tx_len);
227 }
228 
gc9x01x_regs_init(const struct device * dev)229 static int gc9x01x_regs_init(const struct device *dev)
230 {
231 	const struct gc9x01x_config *config = dev->config;
232 	const struct gc9x01x_regs *regs = config->regs;
233 	int ret;
234 
235 	if (!device_is_ready(config->mipi_dev)) {
236 		return -ENODEV;
237 	}
238 
239 	/* Enable inter-command mode */
240 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN1, NULL, 0);
241 	if (ret < 0) {
242 		return ret;
243 	}
244 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN2, NULL, 0);
245 	if (ret < 0) {
246 		return ret;
247 	}
248 
249 	/* Apply default init sequence */
250 	for (int i = 0; (i < ARRAY_SIZE(default_init_regs)) && (ret == 0); i++) {
251 		ret = gc9x01x_transmit(dev, default_init_regs[i].cmd, default_init_regs[i].data,
252 				       default_init_regs[i].len);
253 		if (ret < 0) {
254 			return ret;
255 		}
256 	}
257 
258 	/* Apply generic configuration */
259 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL2, regs->pwrctrl2, sizeof(regs->pwrctrl2));
260 	if (ret < 0) {
261 		return ret;
262 	}
263 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL3, regs->pwrctrl3, sizeof(regs->pwrctrl3));
264 	if (ret < 0) {
265 		return ret;
266 	}
267 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL4, regs->pwrctrl4, sizeof(regs->pwrctrl4));
268 	if (ret < 0) {
269 		return ret;
270 	}
271 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA1, regs->gamma1, sizeof(regs->gamma1));
272 	if (ret < 0) {
273 		return ret;
274 	}
275 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA2, regs->gamma2, sizeof(regs->gamma2));
276 	if (ret < 0) {
277 		return ret;
278 	}
279 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA3, regs->gamma3, sizeof(regs->gamma3));
280 	if (ret < 0) {
281 		return ret;
282 	}
283 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA4, regs->gamma4, sizeof(regs->gamma4));
284 	if (ret < 0) {
285 		return ret;
286 	}
287 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_FRAMERATE, regs->framerate,
288 			       sizeof(regs->framerate));
289 	if (ret < 0) {
290 		return ret;
291 	}
292 
293 	/* Enable Tearing line */
294 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_TEON, NULL, 0);
295 	if (ret < 0) {
296 		return ret;
297 	}
298 
299 	return 0;
300 }
301 
gc9x01x_exit_sleep(const struct device * dev)302 static int gc9x01x_exit_sleep(const struct device *dev)
303 {
304 	int ret;
305 
306 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPOUT, NULL, 0);
307 	if (ret < 0) {
308 		return ret;
309 	}
310 
311 	/*
312 	 * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for
313 	 * any manufacturing defects.
314 	 * This is to allow time for the supply voltages and clock circuits stabilize
315 	 */
316 	k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30);
317 
318 	return 0;
319 }
320 
321 #ifdef CONFIG_PM_DEVICE
gc9x01x_enter_sleep(const struct device * dev)322 static int gc9x01x_enter_sleep(const struct device *dev)
323 {
324 	int ret;
325 
326 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPIN, NULL, 0);
327 	if (ret < 0) {
328 		return ret;
329 	}
330 
331 	/*
332 	 * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for
333 	 * any manufacturing defects.
334 	 */
335 	k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30);
336 
337 	return 0;
338 }
339 #endif
340 
gc9x01x_hw_reset(const struct device * dev)341 static int gc9x01x_hw_reset(const struct device *dev)
342 {
343 	const struct gc9x01x_config *config = dev->config;
344 	int ret;
345 
346 	ret = mipi_dbi_reset(config->mipi_dev, 100);
347 	if (ret < 0) {
348 		return ret;
349 	}
350 	k_msleep(10);
351 
352 	return ret;
353 }
354 
gc9x01x_display_blanking_off(const struct device * dev)355 static int gc9x01x_display_blanking_off(const struct device *dev)
356 {
357 	LOG_DBG("Turning display blanking off");
358 	return gc9x01x_transmit(dev, GC9X01X_CMD_DISPON, NULL, 0);
359 }
360 
gc9x01x_display_blanking_on(const struct device * dev)361 static int gc9x01x_display_blanking_on(const struct device *dev)
362 {
363 	LOG_DBG("Turning display blanking on");
364 	return gc9x01x_transmit(dev, GC9X01X_CMD_DISPOFF, NULL, 0);
365 }
366 
gc9x01x_set_pixel_format(const struct device * dev,const enum display_pixel_format pixel_format)367 static int gc9x01x_set_pixel_format(const struct device *dev,
368 				    const enum display_pixel_format pixel_format)
369 {
370 	struct gc9x01x_data *data = dev->data;
371 	int ret;
372 	uint8_t tx_data;
373 	uint8_t bytes_per_pixel;
374 
375 	if (pixel_format == PIXEL_FORMAT_RGB_565) {
376 		bytes_per_pixel = 2U;
377 		tx_data = GC9X01X_PIXFMT_VAL_MCU_16_BIT | GC9X01X_PIXFMT_VAL_RGB_16_BIT;
378 	} else if (pixel_format == PIXEL_FORMAT_RGB_888) {
379 		bytes_per_pixel = 3U;
380 		tx_data = GC9X01X_PIXFMT_VAL_MCU_18_BIT | GC9X01X_PIXFMT_VAL_RGB_18_BIT;
381 	} else {
382 		LOG_ERR("Unsupported pixel format");
383 		return -ENOTSUP;
384 	}
385 
386 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_PIXFMT, &tx_data, 1U);
387 	if (ret < 0) {
388 		return ret;
389 	}
390 
391 	data->pixel_format = pixel_format;
392 	data->bytes_per_pixel = bytes_per_pixel;
393 
394 	return 0;
395 }
396 
gc9x01x_set_orientation(const struct device * dev,const enum display_orientation orientation)397 static int gc9x01x_set_orientation(const struct device *dev,
398 				   const enum display_orientation orientation)
399 {
400 	struct gc9x01x_data *data = dev->data;
401 	int ret;
402 	uint8_t tx_data = GC9X01X_MADCTL_VAL_BGR;
403 
404 	if (orientation == DISPLAY_ORIENTATION_NORMAL) {
405 		/* works 0° - default */
406 	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) {
407 		/* works CW 90° */
408 		tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MY;
409 	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) {
410 		/* works CW 180° */
411 		tx_data |= GC9X01X_MADCTL_VAL_MY | GC9X01X_MADCTL_VAL_MX | GC9X01X_MADCTL_VAL_MH;
412 	} else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) {
413 		/* works CW 270° */
414 		tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MX;
415 	}
416 
417 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_MADCTL, &tx_data, 1U);
418 	if (ret < 0) {
419 		return ret;
420 	}
421 
422 	data->orientation = orientation;
423 
424 	return 0;
425 }
426 
gc9x01x_configure(const struct device * dev)427 static int gc9x01x_configure(const struct device *dev)
428 {
429 	const struct gc9x01x_config *config = dev->config;
430 	int ret;
431 
432 	/* Set all the required registers. */
433 	ret = gc9x01x_regs_init(dev);
434 	if (ret < 0) {
435 		return ret;
436 	}
437 
438 	/* Pixel format */
439 	ret = gc9x01x_set_pixel_format(dev, config->pixel_format);
440 	if (ret < 0) {
441 		return ret;
442 	}
443 
444 	/* Orientation */
445 	ret = gc9x01x_set_orientation(dev, config->orientation);
446 	if (ret < 0) {
447 		return ret;
448 	}
449 
450 	/* Display inversion mode. */
451 	if (config->inversion) {
452 		ret = gc9x01x_transmit(dev, GC9X01X_CMD_INVON, NULL, 0);
453 		if (ret < 0) {
454 			return ret;
455 		}
456 	}
457 
458 	return 0;
459 }
460 
gc9x01x_init(const struct device * dev)461 static int gc9x01x_init(const struct device *dev)
462 {
463 	int ret;
464 
465 	gc9x01x_hw_reset(dev);
466 
467 	gc9x01x_display_blanking_on(dev);
468 
469 	ret = gc9x01x_configure(dev);
470 	if (ret < 0) {
471 		LOG_ERR("Could not configure display (%d)", ret);
472 		return ret;
473 	}
474 
475 	ret = gc9x01x_exit_sleep(dev);
476 	if (ret < 0) {
477 		LOG_ERR("Could not exit sleep mode (%d)", ret);
478 		return ret;
479 	}
480 
481 	return 0;
482 }
483 
gc9x01x_set_mem_area(const struct device * dev,const uint16_t x,const uint16_t y,const uint16_t w,const uint16_t h)484 static int gc9x01x_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y,
485 				const uint16_t w, const uint16_t h)
486 {
487 	int ret;
488 	uint16_t spi_data[2];
489 
490 	spi_data[0] = sys_cpu_to_be16(x);
491 	spi_data[1] = sys_cpu_to_be16(x + w - 1U);
492 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_COLSET, &spi_data[0], 4U);
493 	if (ret < 0) {
494 		return ret;
495 	}
496 
497 	spi_data[0] = sys_cpu_to_be16(y);
498 	spi_data[1] = sys_cpu_to_be16(y + h - 1U);
499 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_ROWSET, &spi_data[0], 4U);
500 	if (ret < 0) {
501 		return ret;
502 	}
503 
504 	return 0;
505 }
506 
gc9x01x_write(const struct device * dev,const uint16_t x,const uint16_t y,const struct display_buffer_descriptor * desc,const void * buf)507 static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint16_t y,
508 			 const struct display_buffer_descriptor *desc, const void *buf)
509 {
510 	const struct gc9x01x_config *config = dev->config;
511 	struct gc9x01x_data *data = dev->data;
512 	int ret;
513 	const uint8_t *write_data_start = (const uint8_t *)buf;
514 	struct display_buffer_descriptor mipi_desc;
515 	uint16_t write_cnt;
516 	uint16_t nbr_of_writes;
517 	uint16_t write_h;
518 
519 	__ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width");
520 	__ASSERT((desc->pitch * data->bytes_per_pixel * desc->height) <= desc->buf_size,
521 		 "Input buffer to small");
522 
523 	LOG_DBG("Writing %dx%d (w,h) @ %dx%d (x,y)", desc->width, desc->height, x, y);
524 	ret = gc9x01x_set_mem_area(dev, x, y, desc->width, desc->height);
525 	if (ret < 0) {
526 		return ret;
527 	}
528 
529 	if (desc->pitch > desc->width) {
530 		write_h = 1U;
531 		nbr_of_writes = desc->height;
532 		mipi_desc.height = 1;
533 		mipi_desc.buf_size = desc->pitch * data->bytes_per_pixel;
534 	} else {
535 		write_h = desc->height;
536 		mipi_desc.height = desc->height;
537 		mipi_desc.buf_size = desc->width * data->bytes_per_pixel * write_h;
538 		nbr_of_writes = 1U;
539 	}
540 
541 	mipi_desc.width = desc->width;
542 	/* Per MIPI API, pitch must always match width */
543 	mipi_desc.pitch = desc->width;
544 
545 	ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, NULL, 0);
546 	if (ret < 0) {
547 		return ret;
548 	}
549 
550 	for (write_cnt = 0U; write_cnt < nbr_of_writes; ++write_cnt) {
551 		ret = mipi_dbi_write_display(config->mipi_dev,
552 					     &config->dbi_config,
553 					     write_data_start,
554 					     &mipi_desc,
555 					     data->pixel_format);
556 		if (ret < 0) {
557 			return ret;
558 		}
559 
560 		write_data_start += desc->pitch * data->bytes_per_pixel;
561 	}
562 
563 	return 0;
564 }
565 
gc9x01x_get_capabilities(const struct device * dev,struct display_capabilities * capabilities)566 static void gc9x01x_get_capabilities(const struct device *dev,
567 				     struct display_capabilities *capabilities)
568 {
569 	struct gc9x01x_data *data = dev->data;
570 	const struct gc9x01x_config *config = dev->config;
571 
572 	memset(capabilities, 0, sizeof(struct display_capabilities));
573 
574 	capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | PIXEL_FORMAT_RGB_888;
575 	capabilities->current_pixel_format = data->pixel_format;
576 
577 	if (data->orientation == DISPLAY_ORIENTATION_NORMAL ||
578 	    data->orientation == DISPLAY_ORIENTATION_ROTATED_180) {
579 		capabilities->x_resolution = config->x_resolution;
580 		capabilities->y_resolution = config->y_resolution;
581 	} else {
582 		capabilities->x_resolution = config->y_resolution;
583 		capabilities->y_resolution = config->x_resolution;
584 	}
585 
586 	capabilities->current_orientation = data->orientation;
587 }
588 
589 #ifdef CONFIG_PM_DEVICE
gc9x01x_pm_action(const struct device * dev,enum pm_device_action action)590 static int gc9x01x_pm_action(const struct device *dev, enum pm_device_action action)
591 {
592 	int ret;
593 
594 	switch (action) {
595 	case PM_DEVICE_ACTION_RESUME:
596 		ret = gc9x01x_exit_sleep(dev);
597 		break;
598 	case PM_DEVICE_ACTION_SUSPEND:
599 		ret = gc9x01x_enter_sleep(dev);
600 		break;
601 	default:
602 		ret = -ENOTSUP;
603 		break;
604 	}
605 
606 	return ret;
607 }
608 #endif /* CONFIG_PM_DEVICE */
609 
610 /* Device driver API*/
611 static const struct display_driver_api gc9x01x_api = {
612 	.blanking_on = gc9x01x_display_blanking_on,
613 	.blanking_off = gc9x01x_display_blanking_off,
614 	.write = gc9x01x_write,
615 	.get_capabilities = gc9x01x_get_capabilities,
616 	.set_pixel_format = gc9x01x_set_pixel_format,
617 	.set_orientation = gc9x01x_set_orientation,
618 };
619 
620 #define GC9X01X_INIT(inst)                                                                         \
621 	GC9X01X_REGS_INIT(inst);                                                                   \
622 	static const struct gc9x01x_config gc9x01x_config_##inst = {                               \
623 		.mipi_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                                   \
624 		.dbi_config = {                                                                    \
625 			.mode = MIPI_DBI_MODE_SPI_4WIRE,                                           \
626 			.config = MIPI_DBI_SPI_CONFIG_DT_INST(inst,                                \
627 							      SPI_OP_MODE_MASTER |                 \
628 							      SPI_WORD_SET(8), 0),                 \
629 		},                                                                                 \
630 		.pixel_format = DT_INST_PROP(inst, pixel_format),                                  \
631 		.orientation = DT_INST_ENUM_IDX(inst, orientation),                                \
632 		.x_resolution = DT_INST_PROP(inst, width),                                         \
633 		.y_resolution = DT_INST_PROP(inst, height),                                        \
634 		.inversion = DT_INST_PROP(inst, display_inversion),                                \
635 		.regs = &gc9x01x_regs_##inst,                                                      \
636 	};                                                                                         \
637 	static struct gc9x01x_data gc9x01x_data_##inst;                                            \
638 	PM_DEVICE_DT_INST_DEFINE(inst, gc9x01x_pm_action);                                         \
639 	DEVICE_DT_INST_DEFINE(inst, &gc9x01x_init, PM_DEVICE_DT_INST_GET(inst),                    \
640 			      &gc9x01x_data_##inst, &gc9x01x_config_##inst, POST_KERNEL,           \
641 			      CONFIG_DISPLAY_INIT_PRIORITY, &gc9x01x_api);
642 
643 DT_INST_FOREACH_STATUS_OKAY(GC9X01X_INIT)
644