diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index fd655f1894f..30e31ed2b11 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_ST7789V display_st7789v.c) zephyr_library_sources_ifdef(CONFIG_ST7735R display_st7735r.c) zephyr_library_sources_ifdef(CONFIG_STM32_LTDC display_stm32_ltdc.c) zephyr_library_sources_ifdef(CONFIG_RM68200 display_rm68200.c) +zephyr_library_sources_ifdef(CONFIG_RM67162 display_rm67162.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 35521077d44..6654f14d87e 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -33,6 +33,7 @@ source "drivers/display/Kconfig.stm32_ltdc" source "drivers/display/Kconfig.uc81xx" source "drivers/display/Kconfig.dummy" source "drivers/display/Kconfig.ls0xx" +source "drivers/display/Kconfig.rm67162" source "drivers/display/Kconfig.rm68200" source "drivers/display/Kconfig.max7219" source "drivers/display/Kconfig.intel_multibootfb" diff --git a/drivers/display/Kconfig.rm67162 b/drivers/display/Kconfig.rm67162 new file mode 100644 index 00000000000..9f8e0136242 --- /dev/null +++ b/drivers/display/Kconfig.rm67162 @@ -0,0 +1,10 @@ +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +config RM67162 + bool "RM67162 display driver" + default y + select MIPI_DSI + depends on DT_HAS_RAYDIUM_RM67162_ENABLED + help + Enable driver for RM67162 display driver. diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c new file mode 100644 index 00000000000..c23abef6dc0 --- /dev/null +++ b/drivers/display/display_rm67162.c @@ -0,0 +1,610 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raydium_rm67162 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(rm67162, CONFIG_DISPLAY_LOG_LEVEL); + +/* + * These commands are taken from NXP's MCUXpresso SDK. + * Additional documentation is added where possible, but the + * Manufacture command set pages are not described in the datasheet + */ +static const struct { + uint8_t cmd; + uint8_t param; +} rm67162_init_400x392[] = { + /* CMD Mode switch, select manufacture command set page 0 */ + {.cmd = 0xFE, .param = 0x01}, + {.cmd = 0x06, .param = 0x62}, + {.cmd = 0x0E, .param = 0x80}, + {.cmd = 0x0F, .param = 0x80}, + {.cmd = 0x10, .param = 0x71}, + {.cmd = 0x13, .param = 0x81}, + {.cmd = 0x14, .param = 0x81}, + {.cmd = 0x15, .param = 0x82}, + {.cmd = 0x16, .param = 0x82}, + {.cmd = 0x18, .param = 0x88}, + {.cmd = 0x19, .param = 0x55}, + {.cmd = 0x1A, .param = 0x10}, + {.cmd = 0x1C, .param = 0x99}, + {.cmd = 0x1D, .param = 0x03}, + {.cmd = 0x1E, .param = 0x03}, + {.cmd = 0x1F, .param = 0x03}, + {.cmd = 0x20, .param = 0x03}, + {.cmd = 0x25, .param = 0x03}, + {.cmd = 0x26, .param = 0x8D}, + {.cmd = 0x2A, .param = 0x03}, + {.cmd = 0x2B, .param = 0x8D}, + {.cmd = 0x36, .param = 0x00}, + {.cmd = 0x37, .param = 0x10}, + {.cmd = 0x3A, .param = 0x00}, + {.cmd = 0x3B, .param = 0x00}, + {.cmd = 0x3D, .param = 0x20}, + {.cmd = 0x3F, .param = 0x3A}, + {.cmd = 0x40, .param = 0x30}, + {.cmd = 0x41, .param = 0x30}, + {.cmd = 0x42, .param = 0x33}, + {.cmd = 0x43, .param = 0x22}, + {.cmd = 0x44, .param = 0x11}, + {.cmd = 0x45, .param = 0x66}, + {.cmd = 0x46, .param = 0x55}, + {.cmd = 0x47, .param = 0x44}, + {.cmd = 0x4C, .param = 0x33}, + {.cmd = 0x4D, .param = 0x22}, + {.cmd = 0x4E, .param = 0x11}, + {.cmd = 0x4F, .param = 0x66}, + {.cmd = 0x50, .param = 0x55}, + {.cmd = 0x51, .param = 0x44}, + {.cmd = 0x57, .param = 0xB3}, + {.cmd = 0x6B, .param = 0x19}, + {.cmd = 0x70, .param = 0x55}, + {.cmd = 0x74, .param = 0x0C}, + + /* VGMP/VGSP Voltage Control (select manufacture command set page 1 ) */ + {.cmd = 0xFE, .param = 0x02}, + {.cmd = 0x9B, .param = 0x40}, + {.cmd = 0x9C, .param = 0x67}, + {.cmd = 0x9D, .param = 0x20}, + + /* VGMP/VGSP Voltage Control (select manufacture command set page 2 ) */ + {.cmd = 0xFE, .param = 0x03}, + {.cmd = 0x9B, .param = 0x40}, + {.cmd = 0x9C, .param = 0x67}, + {.cmd = 0x9D, .param = 0x20}, + + /* VSR Command (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x5D, .param = 0x10}, + + /* VSR1 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x00, .param = 0x8D}, + {.cmd = 0x01, .param = 0x00}, + {.cmd = 0x02, .param = 0x01}, + {.cmd = 0x03, .param = 0x01}, + {.cmd = 0x04, .param = 0x10}, + {.cmd = 0x05, .param = 0x01}, + {.cmd = 0x06, .param = 0xA7}, + {.cmd = 0x07, .param = 0x20}, + {.cmd = 0x08, .param = 0x00}, + + /* VSR2 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x09, .param = 0xC2}, + {.cmd = 0x0A, .param = 0x00}, + {.cmd = 0x0B, .param = 0x02}, + {.cmd = 0x0C, .param = 0x01}, + {.cmd = 0x0D, .param = 0x40}, + {.cmd = 0x0E, .param = 0x06}, + {.cmd = 0x0F, .param = 0x01}, + {.cmd = 0x10, .param = 0xA7}, + {.cmd = 0x11, .param = 0x00}, + + /* VSR3 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x12, .param = 0xC2}, + {.cmd = 0x13, .param = 0x00}, + {.cmd = 0x14, .param = 0x02}, + {.cmd = 0x15, .param = 0x01}, + {.cmd = 0x16, .param = 0x40}, + {.cmd = 0x17, .param = 0x07}, + {.cmd = 0x18, .param = 0x01}, + {.cmd = 0x19, .param = 0xA7}, + {.cmd = 0x1A, .param = 0x00}, + + /* VSR4 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x1B, .param = 0x82}, + {.cmd = 0x1C, .param = 0x00}, + {.cmd = 0x1D, .param = 0xFF}, + {.cmd = 0x1E, .param = 0x05}, + {.cmd = 0x1F, .param = 0x60}, + {.cmd = 0x20, .param = 0x02}, + {.cmd = 0x21, .param = 0x01}, + {.cmd = 0x22, .param = 0x7C}, + {.cmd = 0x23, .param = 0x00}, + + /* VSR5 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x24, .param = 0xC2}, + {.cmd = 0x25, .param = 0x00}, + {.cmd = 0x26, .param = 0x04}, + {.cmd = 0x27, .param = 0x02}, + {.cmd = 0x28, .param = 0x70}, + {.cmd = 0x29, .param = 0x05}, + {.cmd = 0x2A, .param = 0x74}, + {.cmd = 0x2B, .param = 0x8D}, + {.cmd = 0x2D, .param = 0x00}, + + /* VSR6 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x2F, .param = 0xC2}, + {.cmd = 0x30, .param = 0x00}, + {.cmd = 0x31, .param = 0x04}, + {.cmd = 0x32, .param = 0x02}, + {.cmd = 0x33, .param = 0x70}, + {.cmd = 0x34, .param = 0x07}, + {.cmd = 0x35, .param = 0x74}, + {.cmd = 0x36, .param = 0x8D}, + {.cmd = 0x37, .param = 0x00}, + + /* VSR Marping command (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x5E, .param = 0x20}, + {.cmd = 0x5F, .param = 0x31}, + {.cmd = 0x60, .param = 0x54}, + {.cmd = 0x61, .param = 0x76}, + {.cmd = 0x62, .param = 0x98}, + + /* Select manufacture command set page 4 */ + /* ELVSS -2.4V(RT4723). 0x15: RT4723. 0x01: RT4723B. 0x17: STAM1332. */ + {.cmd = 0xFE, .param = 0x05}, + {.cmd = 0x05, .param = 0x15}, + {.cmd = 0x2A, .param = 0x04}, + {.cmd = 0x91, .param = 0x00}, + + /* Select user command set */ + {.cmd = 0xFE, .param = 0x00}, + /* Set tearing effect signal to only output at V-blank*/ + {.cmd = 0x35, .param = 0x00}, +}; + +#define DSI_TX_MAX_PAYLOAD_BYTE (64U * 4U) + +struct rm67162_config { + const struct device *mipi_dsi; + uint8_t channel; + uint8_t num_of_lanes; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec bl_gpio; + const struct gpio_dt_spec te_gpio; + uint16_t panel_width; + uint16_t panel_height; +}; + + +struct rm67162_data { + uint8_t pixel_format; + uint8_t bytes_per_pixel; + struct gpio_callback te_gpio_cb; + struct k_sem te_sem; +}; + +static void rm67162_te_isr_handler(const struct device *gpio_dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct rm67162_data *data = CONTAINER_OF(cb, struct rm67162_data, te_gpio_cb); + + k_sem_give(&data->te_sem); +} + +static int rm67162_init(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + struct mipi_dsi_device mdev = {0}; + int ret; + uint32_t i; + uint8_t cmd, param; + + /* Attach to MIPI DSI host */ + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = data->pixel_format; + + ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not attach to MIPI-DSI host"); + return ret; + } + + if (config->reset_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + + /* + * Power to the display has been enabled via the regulator fixed api during + * regulator init. Per datasheet, we must wait at least 10ms before + * starting reset sequence after power on. + */ + k_sleep(K_MSEC(10)); + /* Start reset sequence */ + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + LOG_ERR("Could not pull reset low (%d)", ret); + return ret; + } + /* Per datasheet, reset low pulse width should be at least 10usec */ + k_sleep(K_USEC(30)); + gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + LOG_ERR("Could not pull reset high (%d)", ret); + return ret; + } + /* + * It is necessary to wait at least 120msec after releasing reset, + * before sending additional commands. This delay can be 5msec + * if we are certain the display module is in SLEEP IN state, + * but this is not guaranteed (for example, with a warm reset) + */ + k_sleep(K_MSEC(150)); + } + + /* Now, write initialization settings for display, running at 400x392 */ + for (i = 0; i < ARRAY_SIZE(rm67162_init_400x392); i++) { + cmd = rm67162_init_400x392[i].cmd; + param = rm67162_init_400x392[i].param; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd, ¶m, 1); + if (ret < 0) { + return ret; + } + } + + /* Set pixel format */ + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + } else { + /* Unsupported pixel format */ + LOG_ERR("Pixel format not supported"); + return -ENOTSUP; + } + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); + if (ret < 0) { + return ret; + } + + /* Delay 50 ms before exiting sleep mode */ + k_sleep(K_MSEC(50)); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + return ret; + } + /* + * We must wait 5 ms after exiting sleep mode before sending additional + * commands. If we intend to enter sleep mode, we must delay + * 120 ms before sending that command. To be safe, delay 150ms + */ + k_sleep(K_MSEC(150)); + + /* Setup backlight */ + if (config->bl_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure bl GPIO (%d)", ret); + return ret; + } + } + + if (config->te_gpio.port != NULL) { + /* Setup TE pin */ + ret = gpio_pin_configure_dt(&config->te_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure TE GPIO (%d)", ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->te_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure TE interrupt (%d)", ret); + return ret; + } + + /* Init and install GPIO callback */ + gpio_init_callback(&data->te_gpio_cb, rm67162_te_isr_handler, + BIT(config->te_gpio.pin)); + gpio_add_callback(config->te_gpio.port, &data->te_gpio_cb); + + /* Setup te pin semaphore */ + k_sem_init(&data->te_sem, 0, 1); + } + + /* Now, enable display */ + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_DISPLAY_ON, NULL, 0); +} + +/* Helper to write data to rm67162 via MIPI interface. */ +static int rm67162_write_buf(const struct device *dev, bool first_write, + const uint8_t *src, uint32_t len) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + int ret = 0; + uint32_t max_write, wlen; + uint8_t cmd; + + /* + * Max write len: one byte is reserved for DSC command, and + * pixels should not be split across transfers + */ + max_write = ((DSI_TX_MAX_PAYLOAD_BYTE - 1) / data->bytes_per_pixel) * + data->bytes_per_pixel; + if (first_write) { + cmd = MIPI_DCS_WRITE_MEMORY_START; + } else { + cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + while (len > 0) { + /* Cap each tx to max DSI APB transfer size */ + wlen = MIN(max_write, len); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd, src, wlen); + if (ret < 0) { + return ret; + } + /* Advance source pointer and decrement remaining */ + src += wlen; + len -= wlen; + /* All future commands should use WRITE_MEMORY_CONTINUE */ + cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + return ret; +} + +static int rm67162_write(const struct device *dev, const uint16_t x, + const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + int ret; + uint16_t start, end, h_idx; + const uint8_t *src; + bool first_cmd; + uint8_t param[4]; + + LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + + /* + * RM67162 runs in MIPI DBI mode. This means we can use command mode + * to write to the video memory buffer on the RM67162 control IC, + * and the IC will update the display automatically. + */ + + /* Set column address of target area */ + /* First two bytes are starting X coordinate */ + start = x; + end = x + desc->width - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_COLUMN_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + + /* Set page address of target area */ + /* First two bytes are starting Y coordinate */ + start = y; + end = y + desc->height - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PAGE_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + + /* + * Now, write the framebuffer. If the tearing effect GPIO is present, + * wait until the display controller issues an interrupt (which will + * give to the TE semaphore) before sending the frame + */ + if (config->te_gpio.port != NULL) { + if (IS_ENABLED(CONFIG_PM)) { + /* Block sleep state until next TE interrupt + * so we can send frame during that interval + */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); + } + k_sem_take(&data->te_sem, K_FOREVER); + if (IS_ENABLED(CONFIG_PM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); + } + } + src = buf; + first_cmd = true; + + if (desc->pitch == desc->width) { + /* Buffer is contiguous, we can perform entire transfer */ + rm67162_write_buf(dev, first_cmd, src, + desc->height * desc->width * data->bytes_per_pixel); + } else { + /* Buffer is not contiguous, we must write each line separately */ + for (h_idx = 0; h_idx < desc->height; h_idx++) { + rm67162_write_buf(dev, first_cmd, src, + desc->width * data->bytes_per_pixel); + first_cmd = false; + /* The pitch is not equal to width, account for it here */ + src += data->bytes_per_pixel * (desc->pitch - desc->width); + } + } + + return 0; +} + +static void rm67162_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct rm67162_config *config = dev->config; + const struct rm67162_data *data = dev->data; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->panel_width; + capabilities->y_resolution = config->panel_height; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_RGB_888; + switch (data->pixel_format) { + case MIPI_DSI_PIXFMT_RGB565: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; + break; + case MIPI_DSI_PIXFMT_RGB888: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + break; + default: + LOG_WRN("Unsupported display format"); + /* Other display formats not implemented */ + break; + } + capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; +} + +static int rm67162_blanking_off(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 1); + } else { + return -ENOTSUP; + } +} + +static int rm67162_blanking_on(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 0); + } else { + return -ENOTSUP; + } +} + +static int rm67162_set_brightness(const struct device *dev, + const uint8_t brightness) +{ + LOG_WRN("Set brightness not implemented"); + return -ENOTSUP; +} + +static int rm67162_set_contrast(const struct device *dev, + const uint8_t contrast) +{ + LOG_ERR("Set contrast not implemented"); + return -ENOTSUP; +} + +static int rm67162_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + uint8_t param; + + switch (pixel_format) { + case PIXEL_FORMAT_RGB_565: + data->pixel_format = MIPI_DSI_PIXFMT_RGB565; + return 0; + case PIXEL_FORMAT_RGB_888: + data->pixel_format = MIPI_DSI_PIXFMT_RGB888; + return 0; + default: + /* Other display formats not implemented */ + return -ENOTSUP; + } + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + } + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); +} + +static int rm67162_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; + } + LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; +} + +static const struct display_driver_api rm67162_api = { + .blanking_on = rm67162_blanking_on, + .blanking_off = rm67162_blanking_off, + .get_capabilities = rm67162_get_capabilities, + .write = rm67162_write, + .set_brightness = rm67162_set_brightness, + .set_contrast = rm67162_set_contrast, + .set_pixel_format = rm67162_set_pixel_format, + .set_orientation = rm67162_set_orientation, +}; + +#define RM67162_PANEL(id) \ + static const struct rm67162_config rm67162_config_##id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(id)), \ + .num_of_lanes = DT_INST_PROP_BY_IDX(id, data_lanes, 0), \ + .channel = DT_INST_REG_ADDR(id), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(id, reset_gpios, {0}), \ + .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(id, bl_gpios, {0}), \ + .te_gpio = GPIO_DT_SPEC_INST_GET_OR(id, te_gpios, {0}), \ + .panel_width = DT_INST_PROP(id, width), \ + .panel_height = DT_INST_PROP(id, height), \ + }; \ + static struct rm67162_data rm67162_data_##id = { \ + .pixel_format = DT_INST_PROP(id, pixel_format), \ + }; \ + DEVICE_DT_INST_DEFINE(id, \ + &rm67162_init, \ + NULL, \ + &rm67162_data_##id, \ + &rm67162_config_##id, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ + &rm67162_api); + +DT_INST_FOREACH_STATUS_OKAY(RM67162_PANEL) diff --git a/dts/bindings/display/raydium,rm67162.yaml b/dts/bindings/display/raydium,rm67162.yaml new file mode 100644 index 00000000000..3614a861d1f --- /dev/null +++ b/dts/bindings/display/raydium,rm67162.yaml @@ -0,0 +1,31 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Raydium RM67162 Panel + +compatible: "raydium,rm67162" + +include: [mipi-dsi-device.yaml, display-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + + bl-gpios: + type: phandle-array + description: | + The BLn pin is asserted to control the backlight of the panel. + The sensor receives this as an active-high signal. + + te-gpios: + type: phandle-array + description: | + The tearing effect pin is asserted by the controller at a display + VSYNC interval. This permits the controller to send new display + data during a VSYNC interval, removing tearing.