diff --git a/drivers/auxdisplay/CMakeLists.txt b/drivers/auxdisplay/CMakeLists.txt index 654d68921c7..da8b1dcd399 100644 --- a/drivers/auxdisplay/CMakeLists.txt +++ b/drivers/auxdisplay/CMakeLists.txt @@ -6,3 +6,4 @@ 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) +zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_PT6314 auxdisplay_pt6314.c) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 4b3c21cbbb7..f28b463a633 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -23,5 +23,6 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/auxdisplay/Kconfig.hd44780" source "drivers/auxdisplay/Kconfig.itron" source "drivers/auxdisplay/Kconfig.jhd1313" +source "drivers/auxdisplay/Kconfig.pt6314" endif # AUXDISPLAY diff --git a/drivers/auxdisplay/Kconfig.pt6314 b/drivers/auxdisplay/Kconfig.pt6314 new file mode 100644 index 00000000000..7add427e975 --- /dev/null +++ b/drivers/auxdisplay/Kconfig.pt6314 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config AUXDISPLAY_PT6314 + bool "PTC PT6314 dot character VFD driver" + default y + select SPI + depends on DT_HAS_PTC_PT6314_ENABLED + help + Enable driver for PTC PT6314. diff --git a/drivers/auxdisplay/auxdisplay_pt6314.c b/drivers/auxdisplay/auxdisplay_pt6314.c new file mode 100644 index 00000000000..f3676be9b4e --- /dev/null +++ b/drivers/auxdisplay/auxdisplay_pt6314.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2015 Intel Corporation + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Jamie McCrae + * Copyright (c) 2023 Chen Xingyu + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ptc_pt6314 + +#include +#include +#include +#include +#include +#include +#include + +/* Defines for the PT6314_INST_DISPLAY_ON_OFF */ +#define PT6314_DO_BLINKING_ON (1 << 0) +#define PT6314_DO_CURSOR_ON (1 << 1) +#define PT6314_DO_DISPLAY_ON (1 << 2) + +/* Defines for the PT6314_INST_FUNCTION_SET */ +#define PT6314_FS_BRIGHTNESS(BR) (4 - (BR & BIT_MASK(2))) +#define PT6314_FS_ROWS_1 (0 << 3) +#define PT6314_FS_ROWS_2 (1 << 3) +#define PT6314_FS_8BIT_MODE (1 << 4) + +#define PT6314_BRIGHTNESS_MIN 1 +#define PT6314_BRIGHTNESS_MAX 4 + +/* Defines for the PT6314_INST_DDRAM_ADDRESS_SET */ +#define PT6314_DA_BASE_ROW_1 (0x00) +#define PT6314_DA_BASE_ROW_2 (0x40) + +/* Display Commands */ +#define PT6314_INST_CLEAR_DISPLAY BIT(0) +#define PT6314_INST_CURSOR_HOME BIT(1) +#define PT6314_INST_ENTRY_MODE_SET BIT(2) +#define PT6314_INST_DISPLAY_ON_OFF BIT(3) +#define PT6314_INST_CURSOR_OR_DISPLAY_SHIFT BIT(4) +#define PT6314_INST_FUNCTION_SET BIT(5) +#define PT6314_INST_CGRAM_ADDRESS_SET BIT(6) +#define PT6314_INST_DDRAM_ADDRESS_SET BIT(7) + +/* Start Byte */ +#define PT6314_SB_RS_INST (0 << 1) +#define PT6314_SB_RS_DATA (1 << 1) +#define PT6314_SB_RW_WRITE (0 << 2) +#define PT6314_SB_RW_READ (1 << 2) +#define PT6314_SB_SYNC_BITS (BIT_MASK(5) << 3) + +struct auxdisplay_pt6314_data { + bool power; + bool cursor; + bool blinking; + uint8_t brightness; + uint16_t cursor_x; + uint16_t cursor_y; +}; + +struct auxdisplay_pt6314_config { + struct auxdisplay_capabilities capabilities; + struct spi_dt_spec bus; +}; + +static int auxdisplay_pt6314_spi_write(const struct device *dev, uint8_t flags, uint8_t val) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + + uint8_t buf[2] = {PT6314_SB_SYNC_BITS | PT6314_SB_RW_WRITE | flags, val}; + + struct spi_buf tx_buf[] = {{.buf = buf, .len = sizeof(buf)}}; + const struct spi_buf_set tx = {.buffers = tx_buf, .count = 1}; + + return spi_write_dt(&config->bus, &tx); +} + +static inline int auxdisplay_pt6314_inst(const struct device *dev, uint8_t inst) +{ + return auxdisplay_pt6314_spi_write(dev, PT6314_SB_RS_INST, inst); +} + +static inline int auxdisplay_pt6314_data(const struct device *dev, uint8_t data) +{ + return auxdisplay_pt6314_spi_write(dev, PT6314_SB_RS_DATA, data); +} + +static int auxdisplay_pt6314_display_on_off(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = (data->power ? PT6314_DO_DISPLAY_ON : 0) | (data->cursor ? PT6314_DO_CURSOR_ON : 0) | + (data->blinking ? PT6314_DO_BLINKING_ON : 0); + + return auxdisplay_pt6314_inst(dev, PT6314_INST_DISPLAY_ON_OFF | inst); +} + +static int auxdisplay_pt6314_function_set(const struct device *dev) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = PT6314_FS_8BIT_MODE | + (config->capabilities.rows == 2 ? PT6314_FS_ROWS_2 : PT6314_FS_ROWS_1) | + PT6314_FS_BRIGHTNESS(data->brightness); + + return auxdisplay_pt6314_inst(dev, PT6314_INST_FUNCTION_SET | inst); +} + +static int auxdisplay_pt6314_ddram_address_set(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = (data->cursor_y == 0 ? PT6314_DA_BASE_ROW_1 : PT6314_DA_BASE_ROW_2) + data->cursor_x; + + return auxdisplay_pt6314_inst(dev, PT6314_INST_DDRAM_ADDRESS_SET | inst); +} + +static int auxdisplay_pt6314_display_on(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->power = true; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_display_off(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->power = false; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_cursor_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->cursor = enable; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_position_blinking_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->blinking = enable; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_cursor_position_set(const struct device *dev, + enum auxdisplay_position type, int16_t x, + int16_t y) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + if (type == AUXDISPLAY_POSITION_RELATIVE) { + x += data->cursor_x; + y += data->cursor_y; + } else if (type == AUXDISPLAY_POSITION_RELATIVE_DIRECTION) { + return -EINVAL; + } + + if (x < 0 || y < 0) { + return -EINVAL; + } else if (x >= config->capabilities.columns || y >= config->capabilities.rows) { + return -EINVAL; + } + + data->cursor_x = (uint16_t)x; + data->cursor_y = (uint16_t)y; + + return auxdisplay_pt6314_ddram_address_set(dev); +} + +static int auxdisplay_pt6314_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + *x = (int16_t)data->cursor_x; + *y = (int16_t)data->cursor_y; + + return 0; +} + +static int auxdisplay_pt6314_capabilities_get(const struct device *dev, + struct auxdisplay_capabilities *capabilities) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + + memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities)); + + return 0; +} + +static int auxdisplay_pt6314_clear(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->cursor_x = 0; + data->cursor_y = 0; + + return auxdisplay_pt6314_inst(dev, PT6314_INST_CLEAR_DISPLAY); +} + +static int auxdisplay_pt6314_brightness_set(const struct device *dev, uint8_t brightness) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + if (brightness < PT6314_BRIGHTNESS_MIN || brightness > PT6314_BRIGHTNESS_MAX) { + return -EINVAL; + } + + data->brightness = brightness; + + return auxdisplay_pt6314_function_set(dev); +} + +static int auxdisplay_pt6314_brightness_get(const struct device *dev, uint8_t *brightness) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + *brightness = data->brightness; + + return 0; +} + +static int auxdisplay_pt6314_write(const struct device *dev, const uint8_t *text, uint16_t len) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + int ret; + int16_t i; + + for (i = 0; i < len; i++) { + ret = auxdisplay_pt6314_data(dev, text[i]); + if (ret) { + return ret; + } + + data->cursor_x++; + + if (data->cursor_x == config->capabilities.columns) { + data->cursor_x = 0; + data->cursor_y++; + + if (data->cursor_y == config->capabilities.rows) { + data->cursor_y = 0; + } + + ret = auxdisplay_pt6314_ddram_address_set(dev); + if (ret) { + return ret; + } + } + } + + return 0; +} + +static int auxdisplay_pt6314_init(const struct device *dev) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + if (!device_is_ready(config->bus.bus)) { + return -ENODEV; + } + + auxdisplay_pt6314_function_set(dev); + auxdisplay_pt6314_display_on_off(dev); + auxdisplay_pt6314_clear(dev); + + return 0; +} + +static const struct auxdisplay_driver_api auxdisplay_pt6314_auxdisplay_api = { + .display_on = auxdisplay_pt6314_display_on, + .display_off = auxdisplay_pt6314_display_off, + .cursor_set_enabled = auxdisplay_pt6314_cursor_set_enabled, + .position_blinking_set_enabled = auxdisplay_pt6314_position_blinking_set_enabled, + .cursor_position_set = auxdisplay_pt6314_cursor_position_set, + .cursor_position_get = auxdisplay_pt6314_cursor_position_get, + .capabilities_get = auxdisplay_pt6314_capabilities_get, + .clear = auxdisplay_pt6314_clear, + .brightness_get = auxdisplay_pt6314_brightness_get, + .brightness_set = auxdisplay_pt6314_brightness_set, + .write = auxdisplay_pt6314_write, +}; + +#define AUXDISPLAY_PT6314_INST(n) \ + static const struct auxdisplay_pt6314_config auxdisplay_pt6314_config_##n = { \ + .capabilities = \ + { \ + .columns = DT_INST_PROP(n, columns), \ + .rows = DT_INST_PROP(n, rows), \ + .mode = 0, \ + .brightness.minimum = PT6314_BRIGHTNESS_MIN, \ + .brightness.maximum = PT6314_BRIGHTNESS_MAX, \ + .backlight.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .backlight.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .custom_characters = 0, \ + }, \ + .bus = SPI_DT_SPEC_INST_GET(n, \ + SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | \ + SPI_TRANSFER_MSB | SPI_WORD_SET(8), \ + 0), \ + }; \ + \ + static struct auxdisplay_pt6314_data auxdisplay_pt6314_data_##n = { \ + .power = true, \ + .cursor = false, \ + .blinking = false, \ + .brightness = PT6314_BRIGHTNESS_MAX, \ + .cursor_x = 0, \ + .cursor_y = 0, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &auxdisplay_pt6314_init, NULL, &auxdisplay_pt6314_data_##n, \ + &auxdisplay_pt6314_config_##n, POST_KERNEL, \ + CONFIG_AUXDISPLAY_INIT_PRIORITY, &auxdisplay_pt6314_auxdisplay_api); + +DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_PT6314_INST) diff --git a/dts/bindings/auxdisplay/ptc,pt6314.yaml b/dts/bindings/auxdisplay/ptc,pt6314.yaml new file mode 100644 index 00000000000..56324ba1466 --- /dev/null +++ b/dts/bindings/auxdisplay/ptc,pt6314.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: PTC PT6314 Dot Character VFD Controller/Driver IC + +compatible: "ptc,pt6314" + +include: [auxdisplay-device.yaml, spi-device.yaml] + +properties: + columns: + enum: + - 16 + - 20 + - 24 + + rows: + enum: + - 1 + - 2 diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index c70b9b6e053..d5c32b0a54f 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -481,6 +481,7 @@ powervr PowerVR (deprecated, use img) primux Primux Trading, S.L. probox2 PROBOX2 (by W2COMP Co., Ltd.) prt Protonic Holland +ptc Princeton Technology Corp. pulsedlight PulsedLight, Inc purism Purism, SPC qca Qualcomm Atheros, Inc.