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 rs_line_delay;
74 uint16_t clear_delay;
75 uint16_t boot_delay;
76 };
77
78 static void auxdisplay_hd44780_set_entry_mode(const struct device *dev);
79 static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled);
80 static int auxdisplay_hd44780_clear(const struct device *dev);
81
hd44780_pulse_enable_line(const struct device * dev)82 static void hd44780_pulse_enable_line(const struct device *dev)
83 {
84 const struct auxdisplay_hd44780_config *const config = dev->config;
85
86 gpio_pin_set_dt(&config->e_gpio, 1);
87 k_sleep(K_NSEC(config->enable_line_rise_delay));
88 gpio_pin_set_dt(&config->e_gpio, 0);
89 k_sleep(K_NSEC(config->enable_line_fall_delay));
90 }
91
hd44780_set_rs_rw_lines(const struct device * dev,bool rs,bool rw)92 static inline void hd44780_set_rs_rw_lines(const struct device *dev, bool rs, bool rw)
93 {
94 const struct auxdisplay_hd44780_config *const config = dev->config;
95
96 gpio_pin_set_dt(&config->rs_gpio, rs);
97 if (config->rw_gpio.port) {
98 gpio_pin_set_dt(&config->rw_gpio, rw);
99 }
100
101 k_sleep(K_NSEC(config->rs_line_delay));
102 }
103
hd44780_db_gpios_configure(const struct device * dev,uint8_t lsb_line,gpio_flags_t flags)104 static int hd44780_db_gpios_configure(const struct device *dev, uint8_t lsb_line,
105 gpio_flags_t flags)
106 {
107 const struct auxdisplay_hd44780_config *config = dev->config;
108 int rc;
109
110 for (int line = 7; line >= lsb_line; --line) {
111 rc = gpio_pin_configure_dt(&config->db_gpios[line], flags);
112 if (rc < 0) {
113 return rc;
114 }
115 }
116
117 return 0;
118 }
119
auxdisplay_hd44780_command(const struct device * dev,bool rs,uint8_t cmd,uint8_t mode)120 static void auxdisplay_hd44780_command(const struct device *dev, bool rs,
121 uint8_t cmd, uint8_t mode)
122 {
123 int rc;
124 const struct auxdisplay_hd44780_config *config = dev->config;
125 int8_t i = 7;
126 const int8_t lsb_line = (mode == AUXDISPLAY_HD44780_MODE_8_BIT) ? 0 : 4;
127 int8_t ncommands = (mode == AUXDISPLAY_HD44780_MODE_4_BIT) ? 2 : 1;
128 const bool check_busy_flag = (!config->rw_gpio.port ||
129 (mode == AUXDISPLAY_HD44780_MODE_4_BIT_ONCE)) ?
130 false : true;
131
132 if (check_busy_flag) {
133 bool busy;
134
135 rc = hd44780_db_gpios_configure(dev, lsb_line, GPIO_INPUT | GPIO_PULL_DOWN);
136 if (rc < 0) {
137 LOG_ERR("Configuration of db-gpios as inputs failed: %d", rc);
138 return;
139 }
140
141 hd44780_set_rs_rw_lines(dev, 0, 1);
142 do {
143 hd44780_pulse_enable_line(dev);
144
145 /* We don't care about the other pins. */
146 busy = gpio_pin_get_dt(&config->db_gpios[7]);
147
148 if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
149 /* In this mode we have to initiate two separate readbacks. */
150 hd44780_pulse_enable_line(dev);
151 }
152 } while (busy);
153
154 rc = hd44780_db_gpios_configure(dev, lsb_line, GPIO_OUTPUT);
155 if (rc < 0) {
156 LOG_ERR("Configuration of db-gpios as outputs failed: %d", rc);
157 return;
158 }
159 }
160
161 hd44780_set_rs_rw_lines(dev, rs, 0);
162 while (ncommands--) {
163 for (int8_t line = 7; line >= lsb_line; --line) {
164 gpio_pin_set_dt(&config->db_gpios[line], ((cmd & BIT(i)) ? 1 : 0));
165 --i;
166 }
167
168 hd44780_pulse_enable_line(dev);
169 }
170
171 if (!check_busy_flag) {
172 /* Sleep for a max execution time for a given instruction. */
173 uint16_t cmd_delay_us = (cmd == AUXDISPLAY_HD44780_CMD_CLEAR) ? 1520 : 37;
174
175 k_sleep(K_USEC(cmd_delay_us));
176 }
177 }
178
hd44780_ic_initialize(const struct device * dev)179 static void hd44780_ic_initialize(const struct device *dev)
180 {
181 const struct auxdisplay_hd44780_config *config = dev->config;
182 uint8_t cmd;
183
184 /*
185 * If proper power supply is used to power the HD44780, it initializes correctly
186 * on a reset condition all by itself. However, if the power supply is below
187 * its expectations (e.g. supplying it with some 3.3V Nucleo board),
188 * it won't initialize properly on its own, and the MCU has to carry out
189 * the initialization as listed in the reference manual.
190 * Since we cannot determine it properly in the runtime,
191 * always carry out the initialization procedure.
192 */
193 cmd = AUXDISPLAY_HD44780_CMD_SETUP | AUXDISPLAY_HD44780_8_BIT_CONFIG;
194 auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
195 k_sleep(K_USEC(4100));
196 auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
197 k_sleep(K_USEC(100));
198 auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
199 k_sleep(K_USEC(100));
200
201 if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
202 /* Put display into 4-bit mode */
203 cmd = AUXDISPLAY_HD44780_CMD_SETUP;
204 auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE);
205 }
206
207 /* Configure display */
208 if (config->capabilities.rows > 1) {
209 cmd |= AUXDISPLAY_HD44780_2_LINE_CONFIG;
210 }
211 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
212
213 auxdisplay_hd44780_set_display_mode(dev, false);
214 auxdisplay_hd44780_clear(dev);
215 auxdisplay_hd44780_set_entry_mode(dev);
216
217 auxdisplay_hd44780_set_display_mode(dev, true);
218 }
219
auxdisplay_hd44780_init(const struct device * dev)220 static int auxdisplay_hd44780_init(const struct device *dev)
221 {
222 const struct auxdisplay_hd44780_config *config = dev->config;
223 struct auxdisplay_hd44780_data *data = dev->data;
224 int rc;
225 uint8_t i = 0;
226
227 if (config->capabilities.mode > AUXDISPLAY_HD44780_MODE_8_BIT) {
228 /* This index is reserved for internal driver usage */
229 LOG_ERR("HD44780 mode must be 4 or 8-bit");
230 return -EINVAL;
231 }
232
233 /* Configure and set GPIOs */
234 rc = gpio_pin_configure_dt(&config->rs_gpio, GPIO_OUTPUT);
235
236 if (rc < 0) {
237 LOG_ERR("Configuration of RS GPIO failed: %d", rc);
238 return rc;
239 }
240
241 rc = gpio_pin_configure_dt(&config->e_gpio, GPIO_OUTPUT);
242
243 if (rc < 0) {
244 LOG_ERR("Configuration of E GPIO failed: %d", rc);
245 return rc;
246 }
247
248 if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
249 i = 4;
250 }
251
252 while (i < 8) {
253 if (config->db_gpios[i].port) {
254 rc = gpio_pin_configure_dt(&config->db_gpios[i], GPIO_OUTPUT);
255
256 if (rc < 0) {
257 LOG_ERR("Configuration of DB%d GPIO failed: %d", i, rc);
258 return rc;
259 }
260 } else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT && i > 3) {
261 /* Required pin missing */
262 LOG_ERR("Required DB%d pin missing (DB4-DB7 needed for 4-bit mode)", i);
263 return -EINVAL;
264 } else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_8_BIT) {
265 /* Required pin missing */
266 LOG_ERR("Required DB%d pin missing", i);
267 return -EINVAL;
268 }
269
270 ++i;
271 }
272
273 if (config->rw_gpio.port) {
274 rc = gpio_pin_configure_dt(&config->rw_gpio, GPIO_OUTPUT);
275
276 if (rc < 0) {
277 LOG_ERR("Configuration of RW GPIO failed: %d", rc);
278 return rc;
279 }
280 }
281
282 if (config->backlight_gpio.port) {
283 rc = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT);
284
285 if (rc < 0) {
286 LOG_ERR("Configuration of backlight GPIO failed: %d", rc);
287 return rc;
288 }
289
290 gpio_pin_set_dt(&config->backlight_gpio, 0);
291 }
292
293 data->character_x = 0;
294 data->character_y = 0;
295 data->backlight_state = false;
296 data->cursor_enabled = false;
297 data->position_blink_enabled = false;
298 data->direction = AUXDISPLAY_DIRECTION_RIGHT;
299
300 if (config->boot_delay != 0) {
301 /* Boot delay is set, wait for a period of time for the LCD to become ready to
302 * accept commands
303 */
304 k_sleep(K_MSEC(config->boot_delay));
305 }
306
307 hd44780_ic_initialize(dev);
308
309 return 0;
310 }
311
auxdisplay_hd44780_capabilities_get(const struct device * dev,struct auxdisplay_capabilities * capabilities)312 static int auxdisplay_hd44780_capabilities_get(const struct device *dev,
313 struct auxdisplay_capabilities *capabilities)
314 {
315 const struct auxdisplay_hd44780_config *config = dev->config;
316
317 memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities));
318
319 return 0;
320 }
321
auxdisplay_hd44780_clear(const struct device * dev)322 static int auxdisplay_hd44780_clear(const struct device *dev)
323 {
324 const struct auxdisplay_hd44780_config *config = dev->config;
325 struct auxdisplay_hd44780_data *data = dev->data;
326
327 auxdisplay_hd44780_command(dev, false, AUXDISPLAY_HD44780_CMD_CLEAR,
328 config->capabilities.mode);
329
330 data->character_x = 0;
331 data->character_y = 0;
332
333 k_sleep(K_USEC(config->clear_delay));
334
335 return 0;
336 }
337
auxdisplay_hd44780_set_entry_mode(const struct device * dev)338 static void auxdisplay_hd44780_set_entry_mode(const struct device *dev)
339 {
340 const struct auxdisplay_hd44780_config *config = dev->config;
341 struct auxdisplay_hd44780_data *data = dev->data;
342 uint8_t cmd = AUXDISPLAY_HD44780_CMD_ENTRY_MODE;
343
344 if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
345 cmd |= AUXDISPLAY_HD44780_CURSOR_MOVE_RIGHT;
346 }
347
348 if (data->display_shift) {
349 cmd |= AUXDISPLAY_HD44780_DISPLAY_SHIFT;
350 }
351
352 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
353 }
354
auxdisplay_hd44780_set_display_mode(const struct device * dev,bool enabled)355 static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled)
356 {
357 const struct auxdisplay_hd44780_config *config = dev->config;
358 struct auxdisplay_hd44780_data *data = dev->data;
359 uint8_t cmd = AUXDISPLAY_HD44780_CMD_DISPLAY_MODE;
360
361 if (data->cursor_enabled) {
362 cmd |= AUXDISPLAY_HD44780_CURSOR_ENABLED;
363 }
364
365 if (data->position_blink_enabled) {
366 cmd |= AUXDISPLAY_HD44780_POSITION_BLINK_ENABLED;
367 }
368
369 if (enabled) {
370 cmd |= AUXDISPLAY_HD44780_DISPLAY_ENABLED;
371 }
372
373 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
374 }
375
auxdisplay_hd44780_display_on(const struct device * dev)376 static int auxdisplay_hd44780_display_on(const struct device *dev)
377 {
378 auxdisplay_hd44780_set_display_mode(dev, true);
379 return 0;
380 }
381
auxdisplay_hd44780_display_off(const struct device * dev)382 static int auxdisplay_hd44780_display_off(const struct device *dev)
383 {
384 auxdisplay_hd44780_set_display_mode(dev, false);
385 return 0;
386 }
387
auxdisplay_hd44780_cursor_set_enabled(const struct device * dev,bool enabled)388 static int auxdisplay_hd44780_cursor_set_enabled(const struct device *dev, bool enabled)
389 {
390 struct auxdisplay_hd44780_data *data = dev->data;
391
392 data->cursor_enabled = enabled;
393
394 auxdisplay_hd44780_set_display_mode(dev, true);
395
396 return 0;
397 }
398
auxdisplay_hd44780_position_blinking_set_enabled(const struct device * dev,bool enabled)399 static int auxdisplay_hd44780_position_blinking_set_enabled(const struct device *dev, bool enabled)
400 {
401 struct auxdisplay_hd44780_data *data = dev->data;
402
403 data->position_blink_enabled = enabled;
404
405 auxdisplay_hd44780_set_display_mode(dev, true);
406
407 return 0;
408 }
409
auxdisplay_hd44780_cursor_shift_set(const struct device * dev,uint8_t direction,bool display_shift)410 static int auxdisplay_hd44780_cursor_shift_set(const struct device *dev, uint8_t direction,
411 bool display_shift)
412 {
413 struct auxdisplay_hd44780_data *data = dev->data;
414
415 if (display_shift) {
416 /* Not currently supported */
417 return -EINVAL;
418 }
419
420 data->direction = direction;
421 data->display_shift = (display_shift ? true : false);
422
423 auxdisplay_hd44780_set_entry_mode(dev);
424
425 return 0;
426 }
427
auxdisplay_hd44780_cursor_position_set(const struct device * dev,enum auxdisplay_position type,int16_t x,int16_t y)428 static int auxdisplay_hd44780_cursor_position_set(const struct device *dev,
429 enum auxdisplay_position type, int16_t x,
430 int16_t y)
431 {
432 const struct auxdisplay_hd44780_config *config = dev->config;
433 struct auxdisplay_hd44780_data *data = dev->data;
434 uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET;
435
436 if (type == AUXDISPLAY_POSITION_RELATIVE) {
437 x += (int16_t)data->character_x;
438 y += (int16_t)data->character_y;
439 } else if (type == AUXDISPLAY_POSITION_RELATIVE_DIRECTION) {
440 if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
441 x += (int16_t)data->character_x;
442 y += (int16_t)data->character_y;
443 } else {
444 x -= (int16_t)data->character_x;
445 y -= (int16_t)data->character_y;
446 }
447 }
448
449 /* Check position is valid before applying */
450 if (x < 0 || y < 0) {
451 return -EINVAL;
452 } else if (x >= config->capabilities.columns || y >= config->capabilities.rows) {
453 return -EINVAL;
454 }
455
456 data->character_x = (uint16_t)x;
457 data->character_y = (uint16_t)y;
458 cmd |= config->line_addresses[data->character_y] + data->character_x;
459
460 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
461
462 return 0;
463 }
464
auxdisplay_hd44780_cursor_position_get(const struct device * dev,int16_t * x,int16_t * y)465 static int auxdisplay_hd44780_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y)
466 {
467 struct auxdisplay_hd44780_data *data = dev->data;
468
469 *x = (int16_t)data->character_x;
470 *y = (int16_t)data->character_y;
471
472 return 0;
473 }
474
auxdisplay_hd44780_backlight_get(const struct device * dev,uint8_t * backlight)475 static int auxdisplay_hd44780_backlight_get(const struct device *dev, uint8_t *backlight)
476 {
477 const struct auxdisplay_hd44780_config *config = dev->config;
478 struct auxdisplay_hd44780_data *data = dev->data;
479
480 if (!config->backlight_gpio.port) {
481 return -ENOTSUP;
482 }
483
484 *backlight = (data->backlight_state == true ? 1 : 0);
485
486 return 0;
487 }
488
auxdisplay_hd44780_backlight_set(const struct device * dev,uint8_t backlight)489 static int auxdisplay_hd44780_backlight_set(const struct device *dev, uint8_t backlight)
490 {
491 const struct auxdisplay_hd44780_config *config = dev->config;
492 struct auxdisplay_hd44780_data *data = dev->data;
493
494 if (!config->backlight_gpio.port) {
495 return -ENOTSUP;
496 }
497
498 data->backlight_state = (bool)backlight;
499
500 gpio_pin_set_dt(&config->backlight_gpio, (uint8_t)data->backlight_state);
501
502 return 0;
503 }
504
auxdisplay_hd44780_custom_character_set(const struct device * dev,struct auxdisplay_character * character)505 static int auxdisplay_hd44780_custom_character_set(const struct device *dev,
506 struct auxdisplay_character *character)
507 {
508 const struct auxdisplay_hd44780_config *config = dev->config;
509 struct auxdisplay_hd44780_data *data = dev->data;
510 uint8_t i = 0;
511 uint8_t cmd = AUXDISPLAY_HD44780_CMD_CGRAM_SET | (character->index << 3);
512
513 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
514
515 /* HD44780 accepts 5x8 font but needs 8x8 data to be sent, mask off top 3 bits
516 * for each line sent
517 */
518 while (i < 8) {
519 uint8_t l = 0;
520
521 cmd = 0;
522
523 while (l < 5) {
524 if (character->data[(i * 5) + (4 - l)]) {
525 cmd |= BIT(l);
526 }
527
528 ++l;
529 }
530
531 auxdisplay_hd44780_command(dev, true, cmd, config->capabilities.mode);
532
533 ++i;
534 }
535
536 character->character_code = character->index;
537
538 /* Send last known address to switch back to DDRAM entry mode */
539 cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
540 (config->line_addresses[data->character_y] +
541 data->character_x);
542
543 auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode);
544
545 return 0;
546 }
547
auxdisplay_hd44780_write(const struct device * dev,const uint8_t * text,uint16_t len)548 static int auxdisplay_hd44780_write(const struct device *dev, const uint8_t *text, uint16_t len)
549 {
550 const struct auxdisplay_hd44780_config *config = dev->config;
551 struct auxdisplay_hd44780_data *data = dev->data;
552 uint16_t i = 0;
553
554 while (i < len) {
555 auxdisplay_hd44780_command(dev, true, text[i], config->capabilities.mode);
556 ++i;
557
558 if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) {
559 /* Increment */
560 ++data->character_x;
561
562 if (data->character_x == config->capabilities.columns) {
563 data->character_x = 0;
564 ++data->character_y;
565
566 if (data->character_y == config->capabilities.rows) {
567 data->character_y = 0;
568 }
569
570 /* Send command to set position */
571 uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
572 config->line_addresses[data->character_y];
573 auxdisplay_hd44780_command(dev, false, cmd,
574 config->capabilities.mode);
575 }
576 } else {
577 /* Decrement */
578 if (data->character_x == 0) {
579 data->character_x = config->capabilities.columns - 1;
580
581 if (data->character_y == 0) {
582 data->character_y = config->capabilities.rows - 1;
583 } else {
584 --data->character_y;
585 }
586
587 /* Send command to set position */
588 uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET |
589 (config->line_addresses[data->character_y] +
590 data->character_x);
591 auxdisplay_hd44780_command(dev, false, cmd,
592 config->capabilities.mode);
593 } else {
594 --data->character_x;
595 }
596 }
597 }
598
599 return 0;
600 }
601
602 static DEVICE_API(auxdisplay, auxdisplay_hd44780_auxdisplay_api) = {
603 .display_on = auxdisplay_hd44780_display_on,
604 .display_off = auxdisplay_hd44780_display_off,
605 .cursor_set_enabled = auxdisplay_hd44780_cursor_set_enabled,
606 .position_blinking_set_enabled = auxdisplay_hd44780_position_blinking_set_enabled,
607 .cursor_shift_set = auxdisplay_hd44780_cursor_shift_set,
608 .cursor_position_set = auxdisplay_hd44780_cursor_position_set,
609 .cursor_position_get = auxdisplay_hd44780_cursor_position_get,
610 .capabilities_get = auxdisplay_hd44780_capabilities_get,
611 .clear = auxdisplay_hd44780_clear,
612 .backlight_get = auxdisplay_hd44780_backlight_get,
613 .backlight_set = auxdisplay_hd44780_backlight_set,
614 .custom_character_set = auxdisplay_hd44780_custom_character_set,
615 .write = auxdisplay_hd44780_write,
616 };
617
618 /* Returns desired value if backlight is enabled, otherwise returns not supported value */
619 #define BACKLIGHT_CHECK(inst, value) \
620 COND_CODE_1(DT_PROP_HAS_IDX(DT_DRV_INST(inst), backlight_gpios, 0), (value), \
621 (AUXDISPLAY_LIGHT_NOT_SUPPORTED))
622
623 #define AUXDISPLAY_HD44780_DEVICE(inst) \
624 static struct auxdisplay_hd44780_data auxdisplay_hd44780_data_##inst; \
625 static const struct auxdisplay_hd44780_config auxdisplay_hd44780_config_##inst = { \
626 .capabilities = { \
627 .columns = DT_INST_PROP(inst, columns), \
628 .rows = DT_INST_PROP(inst, rows), \
629 .mode = DT_INST_ENUM_IDX(inst, mode), \
630 .brightness.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \
631 .brightness.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \
632 .backlight.minimum = BACKLIGHT_CHECK(inst, \
633 AUXDISPLAY_HD44780_BACKLIGHT_MIN), \
634 .backlight.maximum = BACKLIGHT_CHECK(inst, \
635 AUXDISPLAY_HD44780_BACKLIGHT_MAX), \
636 .custom_characters = AUXDISPLAY_HD44780_CUSTOM_CHARACTERS, \
637 .custom_character_width = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_WIDTH, \
638 .custom_character_height = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_HEIGHT, \
639 }, \
640 .rs_gpio = GPIO_DT_SPEC_INST_GET(inst, register_select_gpios), \
641 .rw_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, read_write_gpios, {0}), \
642 .e_gpio = GPIO_DT_SPEC_INST_GET(inst, enable_gpios), \
643 .db_gpios[0] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 0, {0}), \
644 .db_gpios[1] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 1, {0}), \
645 .db_gpios[2] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 2, {0}), \
646 .db_gpios[3] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 3, {0}), \
647 .db_gpios[4] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 4), \
648 .db_gpios[5] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 5), \
649 .db_gpios[6] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 6), \
650 .db_gpios[7] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 7), \
651 .line_addresses[0] = DT_INST_PROP_BY_IDX(inst, line_addresses, 0), \
652 .line_addresses[1] = DT_INST_PROP_BY_IDX(inst, line_addresses, 1), \
653 .line_addresses[2] = DT_INST_PROP_BY_IDX(inst, line_addresses, 2), \
654 .line_addresses[3] = DT_INST_PROP_BY_IDX(inst, line_addresses, 3), \
655 .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, backlight_gpios, {0}), \
656 .enable_line_rise_delay = DT_INST_PROP(inst, enable_line_rise_delay_ns), \
657 .enable_line_fall_delay = DT_INST_PROP(inst, enable_line_fall_delay_ns), \
658 .rs_line_delay = DT_INST_PROP(inst, rs_line_delay_ns), \
659 .clear_delay = DT_INST_PROP(inst, clear_command_delay_us), \
660 .boot_delay = DT_INST_PROP(inst, boot_delay_ms), \
661 }; \
662 DEVICE_DT_INST_DEFINE(inst, \
663 &auxdisplay_hd44780_init, \
664 NULL, \
665 &auxdisplay_hd44780_data_##inst, \
666 &auxdisplay_hd44780_config_##inst, \
667 POST_KERNEL, \
668 CONFIG_AUXDISPLAY_INIT_PRIORITY, \
669 &auxdisplay_hd44780_auxdisplay_api);
670
671 DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_HD44780_DEVICE)
672