1 /*
2  * Copyright (c) 2023 Jamie McCrae
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT hit_hd44780
8 
9 #include <string.h>
10 #include <zephyr/device.h>
11 #include <zephyr/devicetree.h>
12 #include <zephyr/drivers/auxdisplay.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/pm/device.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/logging/log.h>
17 
18 LOG_MODULE_REGISTER(auxdisplay_hd44780, CONFIG_AUXDISPLAY_LOG_LEVEL);
19 
20 #define AUXDISPLAY_HD44780_BACKLIGHT_MIN 0
21 #define AUXDISPLAY_HD44780_BACKLIGHT_MAX 1
22 
23 #define AUXDISPLAY_HD44780_CUSTOM_CHARACTERS 8
24 #define AUXDISPLAY_HD44780_CUSTOM_CHARACTER_WIDTH 5
25 #define AUXDISPLAY_HD44780_CUSTOM_CHARACTER_HEIGHT 8
26 
27 enum {
28 	AUXDISPLAY_HD44780_MODE_4_BIT = 0,
29 	AUXDISPLAY_HD44780_MODE_8_BIT = 1,
30 
31 	/* Reserved for internal driver use only */
32 	AUXDISPLAY_HD44780_MODE_4_BIT_ONCE,
33 };
34 
35 /* Display commands */
36 #define AUXDISPLAY_HD44780_CMD_CLEAR 0x01
37 #define AUXDISPLAY_HD44780_CMD_ENTRY_MODE 0x04
38 #define AUXDISPLAY_HD44780_CMD_DISPLAY_MODE 0x08
39 #define AUXDISPLAY_HD44780_CMD_CGRAM_SET 0x40
40 #define AUXDISPLAY_HD44780_CMD_POSITION_SET 0x80
41 #define AUXDISPLAY_HD44780_CMD_SETUP 0x20
42 
43 #define AUXDISPLAY_HD44780_8_BIT_CONFIG 0x10
44 #define AUXDISPLAY_HD44780_2_LINE_CONFIG 0x08
45 
46 #define AUXDISPLAY_HD44780_POSITION_BLINK_ENABLED 0x01
47 #define AUXDISPLAY_HD44780_CURSOR_ENABLED 0x02
48 #define AUXDISPLAY_HD44780_DISPLAY_ENABLED 0x04
49 
50 #define AUXDISPLAY_HD44780_DISPLAY_SHIFT 0x01
51 #define AUXDISPLAY_HD44780_CURSOR_MOVE_RIGHT 0x02
52 
53 struct auxdisplay_hd44780_data {
54 	uint16_t character_x;
55 	uint16_t character_y;
56 	bool cursor_enabled;
57 	bool position_blink_enabled;
58 	uint8_t direction;
59 	bool display_shift;
60 	bool backlight_state;
61 };
62 
63 struct auxdisplay_hd44780_config {
64 	struct auxdisplay_capabilities capabilities;
65 	struct gpio_dt_spec rs_gpio;
66 	struct gpio_dt_spec rw_gpio;
67 	struct gpio_dt_spec e_gpio;
68 	struct gpio_dt_spec db_gpios[8];
69 	struct gpio_dt_spec backlight_gpio;
70 	uint8_t line_addresses[4];
71 	uint16_t enable_line_rise_delay;
72 	uint16_t enable_line_fall_delay;
73 	uint16_t clear_delay;
74 	uint16_t boot_delay;
75 };
76 
77 static void auxdisplay_hd44780_set_entry_mode(const struct device *dev);
78 static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled);
79 
auxdisplay_hd44780_command(const struct device * dev,bool rs,uint8_t cmd,uint8_t mode)80 static void auxdisplay_hd44780_command(const struct device *dev, bool rs, uint8_t cmd,
81 				       uint8_t mode)
82 {
83 	const struct auxdisplay_hd44780_config *config = dev->config;
84 	int8_t i = 7;
85 
86 	if (mode == AUXDISPLAY_HD44780_MODE_8_BIT) {
87 		while (i >= 0) {
88 			gpio_pin_set_dt(&config->db_gpios[i], ((cmd & BIT(i)) ? 1 : 0));
89 			--i;
90 		}
91 	} else {
92 		while (i >= 4) {
93 			gpio_pin_set_dt(&config->db_gpios[i], ((cmd & BIT(i)) ? 1 : 0));
94 			--i;
95 		}
96 	}
97 
98 	gpio_pin_set_dt(&config->rs_gpio, rs);
99 
100 	if (config->rw_gpio.port) {
101 		gpio_pin_set_dt(&config->rw_gpio, 0);
102 	}
103 
104 	gpio_pin_set_dt(&config->e_gpio, 1);
105 	k_sleep(K_USEC(config->enable_line_rise_delay));
106 	gpio_pin_set_dt(&config->e_gpio, 0);
107 	k_sleep(K_USEC(config->enable_line_fall_delay));
108 
109 	if (mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
110 		while (i >= 0) {
111 			gpio_pin_set_dt(&config->db_gpios[(i + 4)], ((cmd & BIT(i)) ? 1 : 0));
112 			--i;
113 		}
114 
115 		gpio_pin_set_dt(&config->e_gpio, 1);
116 		k_sleep(K_USEC(config->enable_line_rise_delay));
117 		gpio_pin_set_dt(&config->e_gpio, 0);
118 		k_sleep(K_USEC(config->enable_line_fall_delay));
119 	}
120 }
121 
auxdisplay_hd44780_init(const struct device * dev)122 static int auxdisplay_hd44780_init(const struct device *dev)
123 {
124 	const struct auxdisplay_hd44780_config *config = dev->config;
125 	struct auxdisplay_hd44780_data *data = dev->data;
126 	int rc;
127 	uint8_t i = 0;
128 	uint8_t cmd = AUXDISPLAY_HD44780_CMD_SETUP | AUXDISPLAY_HD44780_8_BIT_CONFIG;
129 
130 	if (config->capabilities.mode > AUXDISPLAY_HD44780_MODE_8_BIT) {
131 		/* This index is reserved for internal driver usage */
132 		LOG_ERR("HD44780 mode must be 4 or 8-bit");
133 		return -EINVAL;
134 	}
135 
136 	/* Configure and set GPIOs */
137 	rc = gpio_pin_configure_dt(&config->rs_gpio, GPIO_OUTPUT);
138 
139 	if (rc < 0) {
140 		LOG_ERR("Configuration of RS GPIO failed: %d", rc);
141 		return rc;
142 	}
143 
144 	if (config->rw_gpio.port) {
145 		rc = gpio_pin_configure_dt(&config->rw_gpio, GPIO_OUTPUT);
146 
147 		if (rc < 0) {
148 			LOG_ERR("Configuration of RW GPIO failed: %d", rc);
149 			return rc;
150 		}
151 	}
152 
153 	rc = gpio_pin_configure_dt(&config->e_gpio, GPIO_OUTPUT);
154 
155 	if (rc < 0) {
156 		LOG_ERR("Configuration of E GPIO failed: %d", rc);
157 		return rc;
158 	}
159 
160 	if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
161 		i = 4;
162 	}
163 
164 	while (i < 8) {
165 		if (config->db_gpios[i].port) {
166 			rc = gpio_pin_configure_dt(&config->db_gpios[i], GPIO_OUTPUT);
167 
168 			if (rc < 0) {
169 				LOG_ERR("Configuration of DB%d GPIO failed: %d", i, rc);
170 				return rc;
171 			}
172 		} else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT && i > 3) {
173 			/* Required pin missing */
174 			LOG_ERR("Required DB%d pin missing (DB4-DB7 needed for 4-bit mode)", i);
175 			return -EINVAL;
176 		} else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_8_BIT) {
177 			/* Required pin missing */
178 			LOG_ERR("Required DB%d pin missing", i);
179 			return -EINVAL;
180 		}
181 
182 		++i;
183 	}
184 
185 	if (config->backlight_gpio.port) {
186 		rc = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT);
187 
188 		if (rc < 0) {
189 			LOG_ERR("Configuration of backlight GPIO failed: %d", rc);
190 			return rc;
191 		}
192 
193 		gpio_pin_set_dt(&config->backlight_gpio, 0);
194 	}
195 
196 	data->character_x = 0;
197 	data->character_y = 0;
198 	data->backlight_state = false;
199 	data->cursor_enabled = false;
200 	data->position_blink_enabled = false;
201 	data->direction = AUXDISPLAY_DIRECTION_RIGHT;
202 
203 	if (config->boot_delay != 0) {
204 		/* Boot delay is set, wait for a period of time for the LCD to become ready to
205 		 * accept commands
206 		 */
207 		k_sleep(K_MSEC(config->boot_delay));
208 	}
209 
210 	if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
211 		/* Reset display to known state in 8-bit mode */
212 		auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
213 		auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
214 
215 		/* Put display into 4-bit mode */
216 		cmd = AUXDISPLAY_HD44780_CMD_SETUP;
217 		auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
218 	}
219 
220 	if (config->capabilities.rows > 1) {
221 		cmd |= AUXDISPLAY_HD44780_2_LINE_CONFIG;
222 	}
223 
224 	/* Configure display */
225 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
226 	auxdisplay_hd44780_set_display_mode(dev, true);
227 	auxdisplay_hd44780_set_entry_mode(dev);
228 	auxdisplay_hd44780_command(dev, false, AUXDISPLAY_HD44780_CMD_CLEAR,
229 				   config->capabilities.mode);
230 
231 	k_sleep(K_USEC(config->clear_delay));
232 
233 	return 0;
234 }
235 
auxdisplay_hd44780_capabilities_get(const struct device * dev,struct auxdisplay_capabilities * capabilities)236 static int auxdisplay_hd44780_capabilities_get(const struct device *dev,
237 					       struct auxdisplay_capabilities *capabilities)
238 {
239 	const struct auxdisplay_hd44780_config *config = dev->config;
240 
241 	memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities));
242 
243 	return 0;
244 }
245 
auxdisplay_hd44780_clear(const struct device * dev)246 static int auxdisplay_hd44780_clear(const struct device *dev)
247 {
248 	const struct auxdisplay_hd44780_config *config = dev->config;
249 	struct auxdisplay_hd44780_data *data = dev->data;
250 
251 	auxdisplay_hd44780_command(dev, false, AUXDISPLAY_HD44780_CMD_CLEAR,
252 				   config->capabilities.mode);
253 
254 	data->character_x = 0;
255 	data->character_y = 0;
256 
257 	k_sleep(K_USEC(config->clear_delay));
258 
259 	return 0;
260 }
261 
auxdisplay_hd44780_set_entry_mode(const struct device * dev)262 static void auxdisplay_hd44780_set_entry_mode(const struct device *dev)
263 {
264 	const struct auxdisplay_hd44780_config *config = dev->config;
265 	struct auxdisplay_hd44780_data *data = dev->data;
266 	uint8_t cmd = AUXDISPLAY_HD44780_CMD_ENTRY_MODE;
267 
268 	if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
269 		cmd |= AUXDISPLAY_HD44780_CURSOR_MOVE_RIGHT;
270 	}
271 
272 	if (data->display_shift) {
273 		cmd |= AUXDISPLAY_HD44780_DISPLAY_SHIFT;
274 	}
275 
276 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
277 }
278 
auxdisplay_hd44780_set_display_mode(const struct device * dev,bool enabled)279 static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled)
280 {
281 	const struct auxdisplay_hd44780_config *config = dev->config;
282 	struct auxdisplay_hd44780_data *data = dev->data;
283 	uint8_t cmd = AUXDISPLAY_HD44780_CMD_DISPLAY_MODE;
284 
285 	if (data->cursor_enabled) {
286 		cmd |= AUXDISPLAY_HD44780_CURSOR_ENABLED;
287 	}
288 
289 	if (data->position_blink_enabled) {
290 		cmd |= AUXDISPLAY_HD44780_POSITION_BLINK_ENABLED;
291 	}
292 
293 	if (enabled) {
294 		cmd |= AUXDISPLAY_HD44780_DISPLAY_ENABLED;
295 	}
296 
297 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
298 }
299 
auxdisplay_hd44780_display_on(const struct device * dev)300 static int auxdisplay_hd44780_display_on(const struct device *dev)
301 {
302 	auxdisplay_hd44780_set_display_mode(dev, true);
303 	return 0;
304 }
305 
auxdisplay_hd44780_display_off(const struct device * dev)306 static int auxdisplay_hd44780_display_off(const struct device *dev)
307 {
308 	auxdisplay_hd44780_set_display_mode(dev, false);
309 	return 0;
310 }
311 
auxdisplay_hd44780_cursor_set_enabled(const struct device * dev,bool enabled)312 static int auxdisplay_hd44780_cursor_set_enabled(const struct device *dev, bool enabled)
313 {
314 	struct auxdisplay_hd44780_data *data = dev->data;
315 
316 	data->cursor_enabled = enabled;
317 
318 	auxdisplay_hd44780_set_display_mode(dev, true);
319 
320 	return 0;
321 }
322 
auxdisplay_hd44780_position_blinking_set_enabled(const struct device * dev,bool enabled)323 static int auxdisplay_hd44780_position_blinking_set_enabled(const struct device *dev, bool enabled)
324 {
325 	struct auxdisplay_hd44780_data *data = dev->data;
326 
327 	data->position_blink_enabled = enabled;
328 
329 	auxdisplay_hd44780_set_display_mode(dev, true);
330 
331 	return 0;
332 }
333 
auxdisplay_hd44780_cursor_shift_set(const struct device * dev,uint8_t direction,bool display_shift)334 static int auxdisplay_hd44780_cursor_shift_set(const struct device *dev, uint8_t direction,
335 					       bool display_shift)
336 {
337 	struct auxdisplay_hd44780_data *data = dev->data;
338 
339 	if (display_shift) {
340 		/* Not currently supported */
341 		return -EINVAL;
342 	}
343 
344 	data->direction = direction;
345 	data->display_shift = (display_shift ? true : false);
346 
347 	auxdisplay_hd44780_set_entry_mode(dev);
348 
349 	return 0;
350 }
351 
auxdisplay_hd44780_cursor_position_set(const struct device * dev,enum auxdisplay_position type,int16_t x,int16_t y)352 static int auxdisplay_hd44780_cursor_position_set(const struct device *dev,
353 						  enum auxdisplay_position type, int16_t x,
354 						  int16_t y)
355 {
356 	const struct auxdisplay_hd44780_config *config = dev->config;
357 	struct auxdisplay_hd44780_data *data = dev->data;
358 	uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET;
359 
360 	if (type == AUXDISPLAY_POSITION_RELATIVE) {
361 		x += (int16_t)data->character_x;
362 		y += (int16_t)data->character_y;
363 	} else if (type == AUXDISPLAY_POSITION_RELATIVE_DIRECTION) {
364 		if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
365 			x += (int16_t)data->character_x;
366 			y += (int16_t)data->character_y;
367 		} else {
368 			x -= (int16_t)data->character_x;
369 			y -= (int16_t)data->character_y;
370 		}
371 	}
372 
373 	/* Check position is valid before applying */
374 	if (x < 0 || y < 0) {
375 		return -EINVAL;
376 	} else if (x >= config->capabilities.columns || y >= config->capabilities.rows) {
377 		return -EINVAL;
378 	}
379 
380 	data->character_x = (uint16_t)x;
381 	data->character_y = (uint16_t)y;
382 	cmd |= config->line_addresses[data->character_y] + data->character_x;
383 
384 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
385 
386 	return 0;
387 }
388 
auxdisplay_hd44780_cursor_position_get(const struct device * dev,int16_t * x,int16_t * y)389 static int auxdisplay_hd44780_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y)
390 {
391 	struct auxdisplay_hd44780_data *data = dev->data;
392 
393 	*x = (int16_t)data->character_x;
394 	*y = (int16_t)data->character_y;
395 
396 	return 0;
397 }
398 
auxdisplay_hd44780_backlight_get(const struct device * dev,uint8_t * backlight)399 static int auxdisplay_hd44780_backlight_get(const struct device *dev, uint8_t *backlight)
400 {
401 	const struct auxdisplay_hd44780_config *config = dev->config;
402 	struct auxdisplay_hd44780_data *data = dev->data;
403 
404 	if (!config->backlight_gpio.port) {
405 		return -ENOTSUP;
406 	}
407 
408 	*backlight = (data->backlight_state == true ? 1 : 0);
409 
410 	return 0;
411 }
412 
auxdisplay_hd44780_backlight_set(const struct device * dev,uint8_t backlight)413 static int auxdisplay_hd44780_backlight_set(const struct device *dev, uint8_t backlight)
414 {
415 	const struct auxdisplay_hd44780_config *config = dev->config;
416 	struct auxdisplay_hd44780_data *data = dev->data;
417 
418 	if (!config->backlight_gpio.port) {
419 		return -ENOTSUP;
420 	}
421 
422 	data->backlight_state = (bool)backlight;
423 
424 	gpio_pin_set_dt(&config->backlight_gpio, (uint8_t)data->backlight_state);
425 
426 	return 0;
427 }
428 
auxdisplay_hd44780_custom_character_set(const struct device * dev,struct auxdisplay_character * character)429 static int auxdisplay_hd44780_custom_character_set(const struct device *dev,
430 						   struct auxdisplay_character *character)
431 {
432 	const struct auxdisplay_hd44780_config *config = dev->config;
433 	struct auxdisplay_hd44780_data *data = dev->data;
434 	uint8_t i = 0;
435 	uint8_t cmd = AUXDISPLAY_HD44780_CMD_CGRAM_SET | (character->index << 3);
436 
437 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
438 
439 	/* HD44780 accepts 5x8 font but needs 8x8 data to be sent, mask off top 3 bits
440 	 * for each line sent
441 	 */
442 	while (i < 8) {
443 		uint8_t l = 0;
444 
445 		cmd = 0;
446 
447 		while (l < 5) {
448 			if (character->data[(i * 5) + (4 - l)]) {
449 				cmd |= BIT(l);
450 			}
451 
452 			++l;
453 		}
454 
455 		auxdisplay_hd44780_command(dev, true, cmd, config->capabilities.mode);
456 
457 		++i;
458 	}
459 
460 	character->character_code = character->index;
461 
462 	/* Send last known address to switch back to DDRAM entry mode */
463 	cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
464 	      (config->line_addresses[data->character_y] +
465 	       data->character_x);
466 
467 	auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
468 
469 	return 0;
470 }
471 
auxdisplay_hd44780_write(const struct device * dev,const uint8_t * text,uint16_t len)472 static int auxdisplay_hd44780_write(const struct device *dev, const uint8_t *text, uint16_t len)
473 {
474 	const struct auxdisplay_hd44780_config *config = dev->config;
475 	struct auxdisplay_hd44780_data *data = dev->data;
476 	uint16_t i = 0;
477 
478 	while (i < len) {
479 		auxdisplay_hd44780_command(dev, true, text[i], config->capabilities.mode);
480 		++i;
481 
482 		if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
483 			/* Increment */
484 			++data->character_x;
485 
486 			if (data->character_x == config->capabilities.columns) {
487 				data->character_x = 0;
488 				++data->character_y;
489 
490 				if (data->character_y == config->capabilities.rows) {
491 					data->character_y = 0;
492 				}
493 
494 				/* Send command to set position */
495 				uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
496 					      config->line_addresses[data->character_y];
497 				auxdisplay_hd44780_command(dev, false, cmd,
498 							config->capabilities.mode);
499 			}
500 		} else {
501 			/* Decrement */
502 			if (data->character_x == 0) {
503 				data->character_x = config->capabilities.columns - 1;
504 
505 				if (data->character_y == 0) {
506 					data->character_y = config->capabilities.rows - 1;
507 				} else {
508 					--data->character_y;
509 				}
510 
511 				/* Send command to set position */
512 				uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
513 					      (config->line_addresses[data->character_y] +
514 					       data->character_x);
515 				auxdisplay_hd44780_command(dev, false, cmd,
516 							config->capabilities.mode);
517 			} else {
518 				--data->character_x;
519 			}
520 		}
521 	}
522 
523 	return 0;
524 }
525 
526 static const struct auxdisplay_driver_api auxdisplay_hd44780_auxdisplay_api = {
527 	.display_on = auxdisplay_hd44780_display_on,
528 	.display_off = auxdisplay_hd44780_display_off,
529 	.cursor_set_enabled = auxdisplay_hd44780_cursor_set_enabled,
530 	.position_blinking_set_enabled = auxdisplay_hd44780_position_blinking_set_enabled,
531 	.cursor_shift_set = auxdisplay_hd44780_cursor_shift_set,
532 	.cursor_position_set = auxdisplay_hd44780_cursor_position_set,
533 	.cursor_position_get = auxdisplay_hd44780_cursor_position_get,
534 	.capabilities_get = auxdisplay_hd44780_capabilities_get,
535 	.clear = auxdisplay_hd44780_clear,
536 	.backlight_get = auxdisplay_hd44780_backlight_get,
537 	.backlight_set = auxdisplay_hd44780_backlight_set,
538 	.custom_character_set = auxdisplay_hd44780_custom_character_set,
539 	.write = auxdisplay_hd44780_write,
540 };
541 
542 /* Returns desired value if backlight is enabled, otherwise returns not supported value */
543 #define BACKLIGHT_CHECK(inst, value)							\
544 	COND_CODE_1(DT_PROP_HAS_IDX(DT_DRV_INST(inst), backlight_gpios, 0), (value),	\
545 		    (AUXDISPLAY_LIGHT_NOT_SUPPORTED))
546 
547 #define AUXDISPLAY_HD44780_DEVICE(inst)								\
548 	static struct auxdisplay_hd44780_data auxdisplay_hd44780_data_##inst;			\
549 	static const struct auxdisplay_hd44780_config auxdisplay_hd44780_config_##inst = {	\
550 		.capabilities = {								\
551 			.columns = DT_INST_PROP(inst, columns),					\
552 			.rows = DT_INST_PROP(inst, rows),					\
553 			.mode = DT_INST_ENUM_IDX(inst, mode),					\
554 			.brightness.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED,			\
555 			.brightness.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED,			\
556 			.backlight.minimum = BACKLIGHT_CHECK(inst,				\
557 							     AUXDISPLAY_HD44780_BACKLIGHT_MIN),	\
558 			.backlight.maximum = BACKLIGHT_CHECK(inst,				\
559 							     AUXDISPLAY_HD44780_BACKLIGHT_MAX),	\
560 			.custom_characters = AUXDISPLAY_HD44780_CUSTOM_CHARACTERS,		\
561 			.custom_character_width = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_WIDTH,	\
562 			.custom_character_height = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_HEIGHT,	\
563 		},										\
564 		.rs_gpio = GPIO_DT_SPEC_INST_GET(inst, register_select_gpios),			\
565 		.rw_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, read_write_gpios, {0}),		\
566 		.e_gpio = GPIO_DT_SPEC_INST_GET(inst, enable_gpios),				\
567 		.db_gpios[0] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 0, {0}),	\
568 		.db_gpios[1] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 1, {0}),	\
569 		.db_gpios[2] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 2, {0}),	\
570 		.db_gpios[3] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 3, {0}),	\
571 		.db_gpios[4] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 4),		\
572 		.db_gpios[5] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 5),		\
573 		.db_gpios[6] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 6),		\
574 		.db_gpios[7] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 7),		\
575 		.line_addresses[0] = DT_INST_PROP_BY_IDX(inst, line_addresses, 0),		\
576 		.line_addresses[1] = DT_INST_PROP_BY_IDX(inst, line_addresses, 1),		\
577 		.line_addresses[2] = DT_INST_PROP_BY_IDX(inst, line_addresses, 2),		\
578 		.line_addresses[3] = DT_INST_PROP_BY_IDX(inst, line_addresses, 3),		\
579 		.backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, backlight_gpios, {0}),		\
580 		.enable_line_rise_delay = DT_INST_PROP(inst, enable_line_rise_delay_us),	\
581 		.enable_line_fall_delay = DT_INST_PROP(inst, enable_line_fall_delay_us),	\
582 		.clear_delay = DT_INST_PROP(inst, clear_command_delay_us),			\
583 		.boot_delay = DT_INST_PROP(inst, boot_delay_ms),				\
584 	};											\
585 	DEVICE_DT_INST_DEFINE(inst,								\
586 			&auxdisplay_hd44780_init,						\
587 			NULL,									\
588 			&auxdisplay_hd44780_data_##inst,					\
589 			&auxdisplay_hd44780_config_##inst,					\
590 			POST_KERNEL,								\
591 			CONFIG_AUXDISPLAY_INIT_PRIORITY,					\
592 			&auxdisplay_hd44780_auxdisplay_api);
593 
594 DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_HD44780_DEVICE)
595