/* * 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)