From 212a4857ba5f28b6b79580c6dcf3c5f943d205dc Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Sun, 15 Jan 2023 11:49:03 +0000 Subject: [PATCH] drivers: auxdisplay: Add Hitachi HD44780 driver Adds an auxiliary display driver for Hitachi HD44780-based (and compatible) LCD displays. Signed-off-by: Jamie McCrae --- drivers/auxdisplay/CMakeLists.txt | 1 + drivers/auxdisplay/Kconfig | 1 + drivers/auxdisplay/Kconfig.hd44780 | 9 + drivers/auxdisplay/auxdisplay_hd44780.c | 594 +++++++++++++++++++++++ dts/bindings/auxdisplay/hit,hd44780.yaml | 88 ++++ 5 files changed, 693 insertions(+) create mode 100644 drivers/auxdisplay/Kconfig.hd44780 create mode 100644 drivers/auxdisplay/auxdisplay_hd44780.c create mode 100644 dts/bindings/auxdisplay/hit,hd44780.yaml diff --git a/drivers/auxdisplay/CMakeLists.txt b/drivers/auxdisplay/CMakeLists.txt index 2cb1c9214c..1cc566fbfe 100644 --- a/drivers/auxdisplay/CMakeLists.txt +++ b/drivers/auxdisplay/CMakeLists.txt @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() +zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_HD44780 auxdisplay_hd44780.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_ITRON auxdisplay_itron.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_JHD1313 auxdisplay_jhd1313.c) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 94c3cff495..4b3c21cbbb 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -20,6 +20,7 @@ module = AUXDISPLAY module-str = auxdisplay source "subsys/logging/Kconfig.template.log_config" +source "drivers/auxdisplay/Kconfig.hd44780" source "drivers/auxdisplay/Kconfig.itron" source "drivers/auxdisplay/Kconfig.jhd1313" diff --git a/drivers/auxdisplay/Kconfig.hd44780 b/drivers/auxdisplay/Kconfig.hd44780 new file mode 100644 index 0000000000..5aadae24c5 --- /dev/null +++ b/drivers/auxdisplay/Kconfig.hd44780 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Jamie McCrae +# SPDX-License-Identifier: Apache-2.0 + +config AUXDISPLAY_HD44780 + bool "Hitachi HD44780 LCD driver" + default y + depends on DT_HAS_HIT_HD44780_ENABLED + help + Enable driver for Hitachi HD44780 and compatible LCDs. diff --git a/drivers/auxdisplay/auxdisplay_hd44780.c b/drivers/auxdisplay/auxdisplay_hd44780.c new file mode 100644 index 0000000000..1d0441a31d --- /dev/null +++ b/drivers/auxdisplay/auxdisplay_hd44780.c @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2023 Jamie McCrae + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT hit_hd44780 + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(auxdisplay_hd44780, CONFIG_AUXDISPLAY_LOG_LEVEL); + +#define AUXDISPLAY_HD44780_BACKLIGHT_MIN 0 +#define AUXDISPLAY_HD44780_BACKLIGHT_MAX 1 + +#define AUXDISPLAY_HD44780_CUSTOM_CHARACTERS 8 +#define AUXDISPLAY_HD44780_CUSTOM_CHARACTER_WIDTH 5 +#define AUXDISPLAY_HD44780_CUSTOM_CHARACTER_HEIGHT 8 + +enum { + AUXDISPLAY_HD44780_MODE_4_BIT = 0, + AUXDISPLAY_HD44780_MODE_8_BIT = 1, + + /* Reserved for internal driver use only */ + AUXDISPLAY_HD44780_MODE_4_BIT_ONCE, +}; + +/* Display commands */ +#define AUXDISPLAY_HD44780_CMD_CLEAR 0x01 +#define AUXDISPLAY_HD44780_CMD_ENTRY_MODE 0x04 +#define AUXDISPLAY_HD44780_CMD_DISPLAY_MODE 0x08 +#define AUXDISPLAY_HD44780_CMD_CGRAM_SET 0x40 +#define AUXDISPLAY_HD44780_CMD_POSITION_SET 0x80 +#define AUXDISPLAY_HD44780_CMD_SETUP 0x20 + +#define AUXDISPLAY_HD44780_8_BIT_CONFIG 0x10 +#define AUXDISPLAY_HD44780_2_LINE_CONFIG 0x08 + +#define AUXDISPLAY_HD44780_POSITION_BLINK_ENABLED 0x01 +#define AUXDISPLAY_HD44780_CURSOR_ENABLED 0x02 +#define AUXDISPLAY_HD44780_DISPLAY_ENABLED 0x04 + +#define AUXDISPLAY_HD44780_DISPLAY_SHIFT 0x01 +#define AUXDISPLAY_HD44780_CURSOR_MOVE_RIGHT 0x02 + +struct auxdisplay_hd44780_data { + uint16_t character_x; + uint16_t character_y; + bool cursor_enabled; + bool position_blink_enabled; + uint8_t direction; + bool display_shift; + bool backlight_state; +}; + +struct auxdisplay_hd44780_config { + struct auxdisplay_capabilities capabilities; + struct gpio_dt_spec rs_gpio; + struct gpio_dt_spec rw_gpio; + struct gpio_dt_spec e_gpio; + struct gpio_dt_spec db_gpios[8]; + struct gpio_dt_spec backlight_gpio; + uint8_t line_addresses[4]; + uint16_t enable_line_rise_delay; + uint16_t enable_line_fall_delay; + uint16_t clear_delay; + uint16_t boot_delay; +}; + +static void auxdisplay_hd44780_set_entry_mode(const struct device *dev); +static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled); + +static void auxdisplay_hd44780_command(const struct device *dev, bool rs, uint8_t cmd, + uint8_t mode) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + int8_t i = 7; + + if (mode == AUXDISPLAY_HD44780_MODE_8_BIT) { + while (i >= 0) { + gpio_pin_set_dt(&config->db_gpios[i], ((cmd & BIT(i)) ? 1 : 0)); + --i; + } + } else { + while (i >= 4) { + gpio_pin_set_dt(&config->db_gpios[i], ((cmd & BIT(i)) ? 1 : 0)); + --i; + } + } + + gpio_pin_set_dt(&config->rs_gpio, rs); + + if (config->rw_gpio.port) { + gpio_pin_set_dt(&config->rw_gpio, 0); + } + + gpio_pin_set_dt(&config->e_gpio, 1); + k_sleep(K_USEC(config->enable_line_rise_delay)); + gpio_pin_set_dt(&config->e_gpio, 0); + k_sleep(K_USEC(config->enable_line_fall_delay)); + + if (mode == AUXDISPLAY_HD44780_MODE_4_BIT) { + while (i >= 0) { + gpio_pin_set_dt(&config->db_gpios[(i + 4)], ((cmd & BIT(i)) ? 1 : 0)); + --i; + } + + gpio_pin_set_dt(&config->e_gpio, 1); + k_sleep(K_USEC(config->enable_line_rise_delay)); + gpio_pin_set_dt(&config->e_gpio, 0); + k_sleep(K_USEC(config->enable_line_fall_delay)); + } +} + +static int auxdisplay_hd44780_init(const struct device *dev) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + int rc; + uint8_t i = 0; + uint8_t cmd = AUXDISPLAY_HD44780_CMD_SETUP | AUXDISPLAY_HD44780_8_BIT_CONFIG; + + if (config->capabilities.mode > AUXDISPLAY_HD44780_MODE_8_BIT) { + /* This index is reserved for internal driver usage */ + LOG_ERR("HD44780 mode must be 4 or 8-bit"); + return -EINVAL; + } + + /* Configure and set GPIOs */ + rc = gpio_pin_configure_dt(&config->rs_gpio, GPIO_OUTPUT); + + if (rc < 0) { + LOG_ERR("Configuration of RS GPIO failed: %d", rc); + return rc; + } + + if (config->rw_gpio.port) { + rc = gpio_pin_configure_dt(&config->rw_gpio, GPIO_OUTPUT); + + if (rc < 0) { + LOG_ERR("Configuration of RW GPIO failed: %d", rc); + return rc; + } + } + + rc = gpio_pin_configure_dt(&config->e_gpio, GPIO_OUTPUT); + + if (rc < 0) { + LOG_ERR("Configuration of E GPIO failed: %d", rc); + return rc; + } + + if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) { + i = 4; + } + + while (i < 8) { + if (config->db_gpios[i].port) { + rc = gpio_pin_configure_dt(&config->db_gpios[i], GPIO_OUTPUT); + + if (rc < 0) { + LOG_ERR("Configuration of DB%d GPIO failed: %d", i, rc); + return rc; + } + } else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT && i > 3) { + /* Required pin missing */ + LOG_ERR("Required DB%d pin missing (DB4-DB7 needed for 4-bit mode)", i); + return -EINVAL; + } else if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_8_BIT) { + /* Required pin missing */ + LOG_ERR("Required DB%d pin missing", i); + return -EINVAL; + } + + ++i; + } + + if (config->backlight_gpio.port) { + rc = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT); + + if (rc < 0) { + LOG_ERR("Configuration of backlight GPIO failed: %d", rc); + return rc; + } + + gpio_pin_set_dt(&config->backlight_gpio, 0); + } + + data->character_x = 0; + data->character_y = 0; + data->backlight_state = false; + data->cursor_enabled = false; + data->position_blink_enabled = false; + data->direction = AUXDISPLAY_DIRECTION_RIGHT; + + if (config->boot_delay != 0) { + /* Boot delay is set, wait for a period of time for the LCD to become ready to + * accept commands + */ + k_sleep(K_MSEC(config->boot_delay)); + } + + if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) { + /* Reset display to known state in 8-bit mode */ + auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE); + auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE); + + /* Put display into 4-bit mode */ + cmd = AUXDISPLAY_HD44780_CMD_SETUP; + auxdisplay_hd44780_command(dev, false, cmd, AUXDISPLAY_HD44780_MODE_4_BIT_ONCE); + } + + if (config->capabilities.rows > 1) { + cmd |= AUXDISPLAY_HD44780_2_LINE_CONFIG; + } + + /* Configure display */ + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); + auxdisplay_hd44780_set_display_mode(dev, true); + auxdisplay_hd44780_set_entry_mode(dev); + auxdisplay_hd44780_command(dev, false, AUXDISPLAY_HD44780_CMD_CLEAR, + config->capabilities.mode); + + k_sleep(K_USEC(config->clear_delay)); + + return 0; +} + +static int auxdisplay_hd44780_capabilities_get(const struct device *dev, + struct auxdisplay_capabilities *capabilities) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + + memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities)); + + return 0; +} + +static int auxdisplay_hd44780_clear(const struct device *dev) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + + auxdisplay_hd44780_command(dev, false, AUXDISPLAY_HD44780_CMD_CLEAR, + config->capabilities.mode); + + data->character_x = 0; + data->character_y = 0; + + k_sleep(K_USEC(config->clear_delay)); + + return 0; +} + +static void auxdisplay_hd44780_set_entry_mode(const struct device *dev) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + uint8_t cmd = AUXDISPLAY_HD44780_CMD_ENTRY_MODE; + + if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) { + cmd |= AUXDISPLAY_HD44780_CURSOR_MOVE_RIGHT; + } + + if (data->display_shift) { + cmd |= AUXDISPLAY_HD44780_DISPLAY_SHIFT; + } + + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); +} + +static void auxdisplay_hd44780_set_display_mode(const struct device *dev, bool enabled) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + uint8_t cmd = AUXDISPLAY_HD44780_CMD_DISPLAY_MODE; + + if (data->cursor_enabled) { + cmd |= AUXDISPLAY_HD44780_CURSOR_ENABLED; + } + + if (data->position_blink_enabled) { + cmd |= AUXDISPLAY_HD44780_POSITION_BLINK_ENABLED; + } + + if (enabled) { + cmd |= AUXDISPLAY_HD44780_DISPLAY_ENABLED; + } + + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); +} + +static int auxdisplay_hd44780_display_on(const struct device *dev) +{ + auxdisplay_hd44780_set_display_mode(dev, true); + return 0; +} + +static int auxdisplay_hd44780_display_off(const struct device *dev) +{ + auxdisplay_hd44780_set_display_mode(dev, false); + return 0; +} + +static int auxdisplay_hd44780_cursor_set_enabled(const struct device *dev, bool enabled) +{ + struct auxdisplay_hd44780_data *data = dev->data; + + data->cursor_enabled = enabled; + + auxdisplay_hd44780_set_display_mode(dev, true); + + return 0; +} + +static int auxdisplay_hd44780_position_blinking_set_enabled(const struct device *dev, bool enabled) +{ + struct auxdisplay_hd44780_data *data = dev->data; + + data->position_blink_enabled = enabled; + + auxdisplay_hd44780_set_display_mode(dev, true); + + return 0; +} + +static int auxdisplay_hd44780_cursor_shift_set(const struct device *dev, uint8_t direction, + bool display_shift) +{ + struct auxdisplay_hd44780_data *data = dev->data; + + if (display_shift) { + /* Not currently supported */ + return -EINVAL; + } + + data->direction = direction; + data->display_shift = (display_shift ? true : false); + + auxdisplay_hd44780_set_entry_mode(dev); + + return 0; +} + +static int auxdisplay_hd44780_cursor_position_set(const struct device *dev, + enum auxdisplay_position type, int16_t x, + int16_t y) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET; + + if (type == AUXDISPLAY_POSITION_RELATIVE) { + x += (int16_t)data->character_x; + y += (int16_t)data->character_y; + } else if (type == AUXDISPLAY_POSITION_RELATIVE_DIRECTION) { + if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) { + x += (int16_t)data->character_x; + y += (int16_t)data->character_y; + } else { + x -= (int16_t)data->character_x; + y -= (int16_t)data->character_y; + } + } + + /* Check position is valid before applying */ + if (x < 0 || y < 0) { + return -EINVAL; + } else if (x >= config->capabilities.columns || y >= config->capabilities.rows) { + return -EINVAL; + } + + data->character_x = (uint16_t)x; + data->character_y = (uint16_t)y; + cmd |= config->line_addresses[data->character_y] + data->character_x; + + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); + + return 0; +} + +static int auxdisplay_hd44780_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y) +{ + struct auxdisplay_hd44780_data *data = dev->data; + + *x = (int16_t)data->character_x; + *y = (int16_t)data->character_y; + + return 0; +} + +static int auxdisplay_hd44780_backlight_get(const struct device *dev, uint8_t *backlight) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + + if (!config->backlight_gpio.port) { + return -ENOTSUP; + } + + *backlight = (data->backlight_state == true ? 1 : 0); + + return 0; +} + +static int auxdisplay_hd44780_backlight_set(const struct device *dev, uint8_t backlight) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + + if (!config->backlight_gpio.port) { + return -ENOTSUP; + } + + data->backlight_state = (bool)backlight; + + gpio_pin_set_dt(&config->backlight_gpio, (uint8_t)data->backlight_state); + + return 0; +} + +static int auxdisplay_hd44780_custom_character_set(const struct device *dev, + struct auxdisplay_character *character) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + uint8_t i = 0; + uint8_t cmd = AUXDISPLAY_HD44780_CMD_CGRAM_SET | (character->index << 3); + + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); + + /* HD44780 accepts 5x8 font but needs 8x8 data to be sent, mask off top 3 bits + * for each line sent + */ + while (i < 8) { + uint8_t l = 0; + + cmd = 0; + + while (l < 5) { + if (character->data[(i * 5) + (4 - l)]) { + cmd |= BIT(l); + } + + ++l; + } + + auxdisplay_hd44780_command(dev, true, cmd, config->capabilities.mode); + + ++i; + } + + character->character_code = character->index; + + /* Send last known address to switch back to DDRAM entry mode */ + cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET | + (config->line_addresses[data->character_y] + + data->character_x); + + auxdisplay_hd44780_command(dev, false, cmd, config->capabilities.mode); + + return 0; +} + +static int auxdisplay_hd44780_write(const struct device *dev, const uint8_t *text, uint16_t len) +{ + const struct auxdisplay_hd44780_config *config = dev->config; + struct auxdisplay_hd44780_data *data = dev->data; + uint16_t i = 0; + + while (i < len) { + auxdisplay_hd44780_command(dev, true, text[i], config->capabilities.mode); + ++i; + + if (data->direction == AUXDISPLAY_DIRECTION_RIGHT) { + /* Increment */ + ++data->character_x; + + if (data->character_x == config->capabilities.columns) { + data->character_x = 0; + ++data->character_y; + + if (data->character_y == config->capabilities.rows) { + data->character_y = 0; + } + + /* Send command to set position */ + uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET | + config->line_addresses[data->character_y]; + auxdisplay_hd44780_command(dev, false, cmd, + config->capabilities.mode); + } + } else { + /* Decrement */ + if (data->character_x == 0) { + data->character_x = config->capabilities.columns - 1; + + if (data->character_y == 0) { + data->character_y = config->capabilities.rows - 1; + } else { + --data->character_y; + } + + /* Send command to set position */ + uint8_t cmd = AUXDISPLAY_HD44780_CMD_POSITION_SET | + (config->line_addresses[data->character_y] + + data->character_x); + auxdisplay_hd44780_command(dev, false, cmd, + config->capabilities.mode); + } else { + --data->character_x; + } + } + } + + return 0; +} + +static const struct auxdisplay_driver_api auxdisplay_hd44780_auxdisplay_api = { + .display_on = auxdisplay_hd44780_display_on, + .display_off = auxdisplay_hd44780_display_off, + .cursor_set_enabled = auxdisplay_hd44780_cursor_set_enabled, + .position_blinking_set_enabled = auxdisplay_hd44780_position_blinking_set_enabled, + .cursor_shift_set = auxdisplay_hd44780_cursor_shift_set, + .cursor_position_set = auxdisplay_hd44780_cursor_position_set, + .cursor_position_get = auxdisplay_hd44780_cursor_position_get, + .capabilities_get = auxdisplay_hd44780_capabilities_get, + .clear = auxdisplay_hd44780_clear, + .backlight_get = auxdisplay_hd44780_backlight_get, + .backlight_set = auxdisplay_hd44780_backlight_set, + .custom_character_set = auxdisplay_hd44780_custom_character_set, + .write = auxdisplay_hd44780_write, +}; + +/* Returns desired value if backlight is enabled, otherwise returns not supported value */ +#define BACKLIGHT_CHECK(inst, value) \ + COND_CODE_1(DT_PROP_HAS_IDX(DT_DRV_INST(inst), backlight_gpios, 0), (value), \ + (AUXDISPLAY_LIGHT_NOT_SUPPORTED)) + +#define AUXDISPLAY_HD44780_DEVICE(inst) \ + static struct auxdisplay_hd44780_data auxdisplay_hd44780_data_##inst; \ + static const struct auxdisplay_hd44780_config auxdisplay_hd44780_config_##inst = { \ + .capabilities = { \ + .columns = DT_INST_PROP(inst, columns), \ + .rows = DT_INST_PROP(inst, rows), \ + .mode = DT_INST_ENUM_IDX(inst, mode), \ + .brightness.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .brightness.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .backlight.minimum = BACKLIGHT_CHECK(inst, \ + AUXDISPLAY_HD44780_BACKLIGHT_MIN), \ + .backlight.maximum = BACKLIGHT_CHECK(inst, \ + AUXDISPLAY_HD44780_BACKLIGHT_MAX), \ + .custom_characters = AUXDISPLAY_HD44780_CUSTOM_CHARACTERS, \ + .custom_character_width = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_WIDTH, \ + .custom_character_height = AUXDISPLAY_HD44780_CUSTOM_CHARACTER_HEIGHT, \ + }, \ + .rs_gpio = GPIO_DT_SPEC_INST_GET(inst, register_select_gpios), \ + .rw_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, read_write_gpios, {0}), \ + .e_gpio = GPIO_DT_SPEC_INST_GET(inst, enable_gpios), \ + .db_gpios[0] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 0, {0}), \ + .db_gpios[1] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 1, {0}), \ + .db_gpios[2] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 2, {0}), \ + .db_gpios[3] = GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, data_bus_gpios, 3, {0}), \ + .db_gpios[4] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 4), \ + .db_gpios[5] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 5), \ + .db_gpios[6] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 6), \ + .db_gpios[7] = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, data_bus_gpios, 7), \ + .line_addresses[0] = DT_INST_PROP_BY_IDX(inst, line_addresses, 0), \ + .line_addresses[1] = DT_INST_PROP_BY_IDX(inst, line_addresses, 1), \ + .line_addresses[2] = DT_INST_PROP_BY_IDX(inst, line_addresses, 2), \ + .line_addresses[3] = DT_INST_PROP_BY_IDX(inst, line_addresses, 3), \ + .backlight_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, backlight_gpios, {0}), \ + .enable_line_rise_delay = DT_INST_PROP(inst, enable_line_rise_delay_us), \ + .enable_line_fall_delay = DT_INST_PROP(inst, enable_line_fall_delay_us), \ + .clear_delay = DT_INST_PROP(inst, clear_command_delay_us), \ + .boot_delay = DT_INST_PROP(inst, boot_delay_ms), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &auxdisplay_hd44780_init, \ + NULL, \ + &auxdisplay_hd44780_data_##inst, \ + &auxdisplay_hd44780_config_##inst, \ + POST_KERNEL, \ + CONFIG_AUXDISPLAY_INIT_PRIORITY, \ + &auxdisplay_hd44780_auxdisplay_api); + +DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_HD44780_DEVICE) diff --git a/dts/bindings/auxdisplay/hit,hd44780.yaml b/dts/bindings/auxdisplay/hit,hd44780.yaml new file mode 100644 index 0000000000..dcf33599de --- /dev/null +++ b/dts/bindings/auxdisplay/hit,hd44780.yaml @@ -0,0 +1,88 @@ +# +# Copyright (c) 2023 Jamie McCrae +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Hitachi HD44780 LCD + +compatible: "hit,hd44780" + +include: [auxdisplay-device.yaml] + +properties: + mode: + type: int + required: true + description: Operating mode of display, 8-bit or 4 for 4-bit mode + enum: + - 4 + - 8 + + register-select-gpios: + type: phandle-array + required: true + description: GPIO connected to Register Select (RS) of LCD + + read-write-gpios: + type: phandle-array + description: Optional GPIO used for selecting read or write mode + + enable-gpios: + type: phandle-array + required: true + description: GPIO used for enabling commands to be sent + + data-bus-gpios: + type: phandle-array + required: true + description: | + Array of GPIOs connected to the DB lines of the display, this must + contain 8 entries ascending from DB0 to DB7, for 4-bit interface + displays, the first 4 must be set as `<0>` + + brightness-gpios: + type: phandle-array + description: Optional GPIO used for controlling the brightness (contrast) + + backlight-gpios: + type: phandle-array + description: Optional GPIO used for enabling the backlight + + line-addresses: + type: uint8-array + default: [0x00, 0x40, 0x14, 0x54] + description: | + Array of addresses for each row, will use defaults if not provided. + Default is as per Hitachi HD44780 specification. + + enable-line-rise-delay-us: + type: int + default: 800 + description: | + Delay time (in us) to wait after enable line rises before setting low. + Default is as per Hitachi HD44780 specification. + + enable-line-fall-delay-us: + type: int + default: 100 + description: | + Delay time (in us) to wait after enable line falls before sending + another command. Default is as per Hitachi HD44780 specification. + + clear-command-delay-us: + type: int + default: 5000 + description: | + Delay time (in us) to wait after issuing a clear command before sending + another command. Default is as per Hitachi HD44780 specification. + + boot-delay-ms: + type: int + default: 0 + description: | + Delay time (in ms) to wait at boot time before sending a command (note: + this will delay startup of the whole application by this time, this + should only be used when time is needed for the display device to be + ready before it can be configured which without any delay would cause + the display to not function properly).