diff --git a/drivers/mipi_dbi/CMakeLists.txt b/drivers/mipi_dbi/CMakeLists.txt index 5f00319bc82..133e24ca626 100644 --- a/drivers/mipi_dbi/CMakeLists.txt +++ b/drivers/mipi_dbi/CMakeLists.txt @@ -3,3 +3,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources_ifdef(CONFIG_MIPI_DBI_SPI mipi_dbi_spi.c) + +zephyr_sources_ifdef(CONFIG_MIPI_DBI_SMARTBOND mipi_dbi_smartbond.c) diff --git a/drivers/mipi_dbi/Kconfig b/drivers/mipi_dbi/Kconfig index f8305d29833..89eaa347b7d 100644 --- a/drivers/mipi_dbi/Kconfig +++ b/drivers/mipi_dbi/Kconfig @@ -23,4 +23,6 @@ config MIPI_DBI_INIT_PRIORITY source "drivers/mipi_dbi/Kconfig.spi" +source "drivers/mipi_dbi/Kconfig.smartbond" + endif diff --git a/drivers/mipi_dbi/Kconfig.smartbond b/drivers/mipi_dbi/Kconfig.smartbond new file mode 100644 index 00000000000..a1fb11a560b --- /dev/null +++ b/drivers/mipi_dbi/Kconfig.smartbond @@ -0,0 +1,12 @@ +# Smartbond MIPI DBI host configuration options + +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config MIPI_DBI_SMARTBOND + bool "Smartbond MIPI DBI host controller driver" + depends on DT_HAS_RENESAS_SMARTBOND_MIPI_DBI_ENABLED + default y + select SPI + help + Enable Smartbond MIPI DBI host controller. diff --git a/drivers/mipi_dbi/mipi_dbi_smartbond.c b/drivers/mipi_dbi/mipi_dbi_smartbond.c new file mode 100644 index 00000000000..6187d38d16e --- /dev/null +++ b/drivers/mipi_dbi/mipi_dbi_smartbond.c @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_mipi_dbi + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(smartbond_mipi_dbi, CONFIG_MIPI_DBI_LOG_LEVEL); + +#define SMARTBOND_IRQN DT_INST_IRQN(0) +#define SMARTBOND_IRQ_PRIO DT_INST_IRQ(0, priority) + +#define PINCTRL_STATE_READ PINCTRL_STATE_PRIV_START + +#define MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED \ + DT_INST_NODE_HAS_PROP(0, spi_dev) + +#define LCDC_SMARTBOND_CLK_DIV(_freq) \ + ((32000000U % (_freq)) ? (96000000U / (_freq)) : (32000000U / (_freq))) + +#define MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED \ + !!(32000000U % DT_PROP(DT_CHOSEN(zephyr_display), mipi_max_frequency)) + +#define MIPI_DBI_SMARTBOND_IS_TE_ENABLED \ + DT_INST_PROP_OR(0, te_enable, 0) + +#define MIPI_DBI_SMARTBOND_IS_DMA_PREFETCH_ENABLED \ + DT_INST_ENUM_IDX_OR(0, dma_prefetch, 0) + +#define MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE \ + DT_INST_NODE_HAS_PROP(0, reset_gpios) + +#define LCDC_LAYER0_OFFSETX_REG_SET_FIELD(_field, _var, _val) \ + ((_var)) = \ + ((_var) & ~(LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Msk)) | \ + (((_var) << LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Pos) & \ + LCDC_LCDC_LAYER0_OFFSETX_REG_ ## _field ## _Msk) + +struct mipi_dbi_smartbond_data { + /* Provide mutual exclusion when a display operation is requested. */ + struct k_sem device_sem; + /* Provide synchronization between task return and ISR firing */ + struct k_sem sync_sem; + /* Flag indicating whether or not an underflow took place */ + volatile bool underflow_flag; + /* Layer settings */ + lcdc_smartbond_layer_cfg layer; +}; + +struct mipi_dbi_smartbond_config { + /* Reference to device instance's pinctrl configurations */ + const struct pinctrl_dev_config *pcfg; + /* Reset GPIO */ + const struct gpio_dt_spec reset; + /* Host controller's timing settings */ + lcdc_smartbond_timing_cfg timing_cfg; + /* Background default color configuration */ + lcdc_smartbond_bgcolor_cfg bgcolor_cfg; +}; + +/* Mark the device is is progress and so it's not allowed to enter the sleep state. */ +static void mipi_dbi_pm_get(const struct device *dev) +{ +#if CONFIG_PM_DEVICE + /* + * By marking the device as busy, PM will not communicate PM events + * to the device via mipi_dbi_smartbond_pm_action. It's OK if PM is + * not used at all. Executing a single frame requires waiting for + * the frame to be completed. As such, the system might enter the idle + * state if no other tasks are pending and for as long as the frame is + * being sent. + * + * XXX: Another option would be to use a flag and mark when the controller + * is in progress so a negative value other than -ENOSYS, -ENOTSUP or + * -EALREADY is returned in mipi_dbi_smartbond_pm_action. Sideffect + * of this approach is that the sleep state will be aborted at all, + * though the system could enter a low-power state, instead (see comment + * below on how to achieve a low-power state). + */ + pm_device_busy_set(dev); +#endif +#if CONFIG_PM + /* + * LCDC controller resides in PD_SYS which is turned off when the system enters + * the extended sleep state. By calling this API, a reference counter is + * incremented, designating that the specific power domain should not be turned off. + * As a result, a low-power state (i.e. ARM WFI) will be selected, instead (when the + * system is idle). + */ + (void)da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS); +#endif +} + +/* Mark that device is inactive and so it's allowed to enter the sleep state */ +static void mipi_dbi_pm_put(const struct device *dev) +{ +#if CONFIG_PM_DEVICE + (void)pm_device_busy_clear(dev); +#endif +#if CONFIG_PM + (void)da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); +#endif +} + +/* Helper function to trigger the LCDC fetching data from frame buffer to the connected display */ +static void mipi_dbi_smartbond_send_single_frame(const struct device *dev) +{ + struct mipi_dbi_smartbond_data *data = dev->data; + +#if MIPI_DBI_SMARTBOND_IS_TE_ENABLED + da1469x_lcdc_te_set_status(true, DT_INST_PROP_OR(0, te_polarity, false)); + /* + * Wait for the TE signal to be asserted so display's refresh status can be synchronized + * with the current frame update. + */ + k_sem_take(&data->sync_sem, K_FOREVER); +#endif + + LCDC->LCDC_INTERRUPT_REG |= LCDC_LCDC_INTERRUPT_REG_LCDC_VSYNC_IRQ_EN_Msk; + + /* Setting this bit will enable the host to start outputing pixel data */ + LCDC->LCDC_MODE_REG |= LCDC_LCDC_MODE_REG_LCDC_SFRAME_UPD_Msk; + + /* Wait for frame update to complete */ + k_sem_take(&data->sync_sem, K_FOREVER); + + if (data->underflow_flag) { + LOG_WRN("Underflow took place"); + data->underflow_flag = false; + } +} + +#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE +static int mipi_dbi_smartbond_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_smartbond_config *config = dev->config; + int ret; + + if (!gpio_is_ready_dt(&config->reset)) { + LOG_ERR("Reset signal not available"); + return -ENODEV; + } + + ret = gpio_pin_set_dt(&config->reset, 1); + if (ret < 0) { + LOG_ERR("Cannot drive reset signal"); + return ret; + } + k_msleep(delay); + + return gpio_pin_set_dt(&config->reset, 0); +} +#endif + +/* Display pixel to output color format translation */ +static inline uint8_t lcdc_smartbond_pixel_to_ocm(enum display_pixel_format pixfmt) +{ + switch (pixfmt) { + case PIXEL_FORMAT_RGB_565: + return (uint8_t)LCDC_SMARTBOND_OCM_RGB565; + case PIXEL_FORMAT_RGB_888: + return (uint8_t)LCDC_SMARTBOND_OCM_RGB888; + case PIXEL_FORMAT_MONO10: + return (uint8_t)LCDC_SMARTBOND_L0_L1; + default: + LOG_ERR("Unsupported pixel format"); + return 0; + }; +} + +static inline uint8_t lcdc_smartbond_line_mode_translation(uint8_t mode) +{ + switch (mode) { + case MIPI_DBI_MODE_SPI_3WIRE: + return (uint8_t)LCDC_SMARTBOND_MODE_SPI3; + case MIPI_DBI_MODE_SPI_4WIRE: + return (uint8_t)LCDC_SMARTBOND_MODE_SPI4; + default: + LOG_ERR("Unsupported SPI mode"); + return 0; + } +} + +static inline uint8_t lcdc_smartbond_pixel_to_lcm(enum display_pixel_format pixfmt) +{ + switch (pixfmt) { + case PIXEL_FORMAT_RGB_565: + return (uint8_t)LCDC_SMARTBOND_L0_RGB565; + case PIXEL_FORMAT_ARGB_8888: + return (uint8_t)LCDC_SMARTBOND_L0_ARGB8888; + default: + LOG_ERR("Unsupported pixel format"); + return 0; + }; +} + +static void lcdc_smartbond_mipi_dbi_translation(const struct mipi_dbi_config *dbi_config, + lcdc_smartbond_mipi_dbi_cfg *mipi_dbi_cfg, + enum display_pixel_format pixfmt) +{ + mipi_dbi_cfg->cpha = dbi_config->config.operation & SPI_MODE_CPHA; + mipi_dbi_cfg->cpol = dbi_config->config.operation & SPI_MODE_CPOL; + mipi_dbi_cfg->cs_active_high = dbi_config->config.operation & SPI_CS_ACTIVE_HIGH; + mipi_dbi_cfg->line_mode = lcdc_smartbond_line_mode_translation(dbi_config->mode); + mipi_dbi_cfg->color_mode = lcdc_smartbond_pixel_to_ocm(pixfmt); +} + +#if MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED +static int mipi_dbi_smartbond_command_read(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t *cmd, size_t num_cmds, + uint8_t *response, size_t len) +{ + struct mipi_dbi_smartbond_data *data = dev->data; + const struct mipi_dbi_smartbond_config *config = dev->config; + int ret = 0; + lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg; + + k_sem_take(&data->device_sem, K_FOREVER); + + /* + * Add an arbitrary valid color format to satisfy subroutine. The MIPI DBI command/data + * engine should not be affected. + */ + lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, PIXEL_FORMAT_RGB_565); + ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg); + if (ret < 0) { + goto _mipi_dbi_read_exit; + } + + /* Check if the cmd/data engine is busy since the #CS line will be overruled. */ + if (da1469x_lcdc_is_busy()) { + LOG_WRN("MIPI DBI host is busy"); + ret = -EBUSY; + goto _mipi_dbi_read_exit; + } + + /* Force CS line to low. Typically, command and data are bound in the same #CS assertion */ + da1469x_lcdc_force_cs_line(true, mipi_dbi_cfg.cs_active_high); + + da1469x_lcdc_send_cmd_data(true, cmd, num_cmds); + + if (len) { + const struct device *spi_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, spi_dev)); + + struct spi_buf buffer = { + .buf = (void *)response, + .len = len, + }; + struct spi_buf_set buf_set = { + .buffers = &buffer, + .count = 1, + }; + + if (!device_is_ready(spi_dev)) { + LOG_ERR("SPI device is not ready"); + ret = -ENODEV; + goto _mipi_dbi_read_exit; + } + + /* Overwrite CLK and enable DI lines. CS is driven forcefully. */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_READ); + if (ret < 0) { + LOG_ERR("Could not apply MIPI DBI pins' SPI read state (%d)", ret); + goto _mipi_dbi_read_exit; + } + + /* Get response */ + ret = spi_read(spi_dev, &dbi_config->config, &buf_set); + if (ret < 0) { + LOG_ERR("Could not read data from SPI"); + goto _mipi_dbi_read_exit; + } + } + +_mipi_dbi_read_exit: + + /* Restore #CS line */ + da1469x_lcdc_force_cs_line(false, mipi_dbi_cfg.cs_active_high); + + /* Make sure default LCDC pins are applied upon exit */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Could not apply MIPI DBI pins' default state (%d)", ret); + } + + k_sem_give(&data->device_sem); + + return ret; +} +#endif + +static int mipi_dbi_smartbond_command_write(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t cmd, const uint8_t *data_buf, + size_t len) +{ + struct mipi_dbi_smartbond_data *data = dev->data; + int ret; + lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg; + + k_sem_take(&data->device_sem, K_FOREVER); + + mipi_dbi_pm_get(dev); + + /* + * Add an arbitrary valid color format to satisfy subroutine. The MIPI DBI command/data + * engine should not be affected. + */ + lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, PIXEL_FORMAT_RGB_565); + ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg); + if (ret < 0) { + k_sem_give(&data->device_sem); + return ret; + } + + /* Command and accompanied data should be transmitted via the DBIB interface */ + da1469x_lcdc_send_cmd_data(true, &cmd, 1); + + if (len) { + /* Data should be transmitted via the DBIB interface */ + da1469x_lcdc_send_cmd_data(false, data_buf, len); + } + + mipi_dbi_pm_put(dev); + + k_sem_give(&data->device_sem); + + return 0; +} + +static int mipi_dbi_smartbond_write_display(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + struct mipi_dbi_smartbond_data *data = dev->data; + const struct mipi_dbi_smartbond_config *config = dev->config; + lcdc_smartbond_layer_cfg *layer = &data->layer; + int ret = 0; + lcdc_smartbond_mipi_dbi_cfg mipi_dbi_cfg; + uint8_t layer_color = lcdc_smartbond_pixel_to_lcm(pixfmt); + + if (desc->width * desc->height * (DISPLAY_BITS_PER_PIXEL(pixfmt) / 8) != + desc->buf_size) { + LOG_ERR("Incorrect buffer size for given width and height"); + return -EINVAL; + } + + k_sem_take(&data->device_sem, K_FOREVER); + + mipi_dbi_pm_get(dev); + + /* + * Mainly check if the frame generator is busy with a pending frame update (might happen + * when two frame updates take place one after the other and the display interface is + * quite slow). VSYNC interrupt line should be asserted when the last line is being + * outputed. + */ + if (da1469x_lcdc_is_busy()) { + LOG_WRN("MIPI DBI host is busy"); + ret = -EBUSY; + goto _mipi_dbi_write_exit; + } + + lcdc_smartbond_mipi_dbi_translation(dbi_config, &mipi_dbi_cfg, pixfmt); + ret = da1469x_lcdc_mipi_dbi_interface_configure(&mipi_dbi_cfg); + if (ret < 0) { + goto _mipi_dbi_write_exit; + } + + ret = da1469x_lcdc_timings_configure(desc->width, desc->height, + (lcdc_smartbond_timing_cfg *)&config->timing_cfg); + if (ret < 0) { + goto _mipi_dbi_write_exit; + } + + LCDC_SMARTBOND_LAYER_CONFIG(layer, framebuf, 0, 0, desc->width, desc->height, + layer_color, + da1469x_lcdc_stride_calculation(layer_color, desc->width)); + ret = da1469x_lcdc_layer_configure(layer); + if (ret < 0) { + goto _mipi_dbi_write_exit; + } + + /* Trigger single frame update via the LCDC-DMA engine */ + mipi_dbi_smartbond_send_single_frame(dev); + +_mipi_dbi_write_exit: + + mipi_dbi_pm_put(dev); + + k_sem_give(&data->device_sem); + + return ret; +} + +static int mipi_dbi_smartbond_configure(const struct device *dev) +{ + uint8_t clk_div = + LCDC_SMARTBOND_CLK_DIV(DT_PROP(DT_CHOSEN(zephyr_display), mipi_max_frequency)); + const struct mipi_dbi_smartbond_config *config = dev->config; + + /* + * First enable the controller so registers can be written. In serial interfaces + * clock divider is further divided by 2. + */ + da1469x_lcdc_set_status(true, MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED, + (clk_div >= 2 ? clk_div / 2 : clk_div)); + + if (!da1469x_lcdc_check_id()) { + LOG_ERR("Mismatching LCDC ID"); + da1469x_lcdc_set_status(false, 0, 0); + return -EINVAL; + } + + da1469x_lcdc_te_set_status(false, DT_INST_PROP_OR(0, te_polarity, false)); + + da1469x_lcdc_bgcolor_configure((lcdc_smartbond_bgcolor_cfg *)&config->bgcolor_cfg); + + LCDC_LAYER0_OFFSETX_REG_SET_FIELD(LCDC_L0_DMA_PREFETCH, + LCDC->LCDC_LAYER0_OFFSETX_REG, MIPI_DBI_SMARTBOND_IS_DMA_PREFETCH_ENABLED); + + return 0; +} + +static void smartbond_mipi_dbi_isr(const void *arg) +{ + struct mipi_dbi_smartbond_data *data = ((const struct device *)arg)->data; + + /* + * Underflow sticky bit will remain high until cleared by writing + * any value to LCDC_INTERRUPT_REG. + */ + data->underflow_flag = LCDC_STATUS_REG_GET_FIELD(LCDC_STICKY_UNDERFLOW); + + /* Default interrupt mode is level triggering so interrupt should be cleared */ + da1469x_lcdc_te_set_status(false, DT_INST_PROP_OR(0, te_polarity, false)); + + k_sem_give(&data->sync_sem); +} + +static int mipi_dbi_smartbond_resume(const struct device *dev) +{ + const struct mipi_dbi_smartbond_config *config = dev->config; + int ret; + + /* Select default state */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Could not apply LCDC pins' default state (%d)", ret); + return -EIO; + } + +#if MIPI_DBI_SMARTBOND_IS_PLL_REQUIRED + const struct device *clock_dev = DEVICE_DT_GET(DT_NODELABEL(osc)); + + if (!device_is_ready(clock_dev)) { + LOG_WRN("Clock device is not available; PLL cannot be used"); + } else { + ret = z_smartbond_select_sys_clk(SMARTBOND_CLK_PLL96M); + if (ret < 0) { + LOG_WRN("Could not switch to PLL. Requested speed should not be achieved."); + } + } +#endif + + return mipi_dbi_smartbond_configure(dev); +} + +#ifdef CONFIG_PM_DEVICE +static int mipi_dbi_smartbond_suspend(const struct device *dev) +{ + const struct mipi_dbi_smartbond_config *config = dev->config; + int ret; + + /* Select sleep state; it's OK if settings fails for any reason. */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + if (ret < 0) { + LOG_WRN("Could not apply MIPI DBI pins' sleep state"); + } + + /* Disable host controller to minimize power consumption. */ + da1469x_lcdc_set_status(false, false, 0); + + return 0; +} + +static int mipi_dbi_smartbond_pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + (void)mipi_dbi_smartbond_suspend(dev); + +#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM + da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS); +#endif + break; + case PM_DEVICE_ACTION_RESUME: + ret = mipi_dbi_smartbond_resume(dev); + +#if CONFIG_PM_DEVICE_RUNTIME && CONFIG_PM + /* + * If resume succeeded, prevent the system from entering the + * extended sleep state (Instead, use __WFI). If not, do not + * as users should not suspend the device and thus releasing + * PD_SYS. + */ + if (ret == 0) { + da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS); + } +#endif + break; + default: + return -ENOTSUP; + } + + return ret; +} +#endif + +static int mipi_dbi_smartbond_init(const struct device *dev) +{ + const struct mipi_dbi_smartbond_config *config = dev->config; + struct mipi_dbi_smartbond_data *data = dev->data; + int ret; + + /* Device should be ready to be acquired */ + k_sem_init(&data->device_sem, 1, 1); + /* Event should be signaled by LCDC ISR */ + k_sem_init(&data->sync_sem, 0, 1); + +#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE + if (gpio_is_ready_dt(&config->reset)) { + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset line (%d)", ret); + return -EIO; + } + } +#endif + + IRQ_CONNECT(SMARTBOND_IRQN, SMARTBOND_IRQ_PRIO, smartbond_mipi_dbi_isr, + DEVICE_DT_INST_GET(0), 0); + +#ifdef CONFIG_PM_DEVICE_RUNTIME + /* Make sure device state is marked as suspended */ + pm_device_init_suspended(dev); + + ret = pm_device_runtime_enable(dev); + if ((ret < 0) && (ret != -ENOSYS)) { + return ret; + } +#else + /* Resme if either PM is not used at all or if PM without runtime is used. */ + ret = mipi_dbi_smartbond_resume(dev); + if (ret < 0) { + return ret; + } +#endif + + return 0; +} + +static struct mipi_dbi_driver_api mipi_dbi_smartbond_driver_api = { +#if MIPI_DBI_SMARTBOND_IS_RESET_AVAILABLE + .reset = mipi_dbi_smartbond_reset, +#endif + .command_write = mipi_dbi_smartbond_command_write, + .write_display = mipi_dbi_smartbond_write_display, +#if MIPI_DBI_SMARTBOND_IS_READ_SUPPORTED + .command_read = mipi_dbi_smartbond_command_read, +#endif +}; + +#define SMARTBOND_MIPI_DBI_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static const struct mipi_dbi_smartbond_config mipi_dbi_smartbond_config_## inst = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), \ + .timing_cfg = { 0 }, \ + .bgcolor_cfg = { 0xFF, 0xFF, 0xFF, 0 }, \ + }; \ + \ + static struct mipi_dbi_smartbond_data mipi_dbi_smartbond_data_## inst; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, mipi_dbi_smartbond_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, mipi_dbi_smartbond_init, \ + PM_DEVICE_DT_INST_GET(inst), \ + &mipi_dbi_smartbond_data_## inst, \ + &mipi_dbi_smartbond_config_## inst, \ + POST_KERNEL, \ + CONFIG_MIPI_DBI_INIT_PRIORITY, \ + &mipi_dbi_smartbond_driver_api); + +SMARTBOND_MIPI_DBI_INIT(0); diff --git a/dts/bindings/mipi-dbi/renesas,smartbond-mipi-dbi.yaml b/dts/bindings/mipi-dbi/renesas,smartbond-mipi-dbi.yaml new file mode 100644 index 00000000000..2bfd857732c --- /dev/null +++ b/dts/bindings/mipi-dbi/renesas,smartbond-mipi-dbi.yaml @@ -0,0 +1,54 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +include: [mipi-dbi-controller.yaml, pinctrl-device.yaml] + +description: Renesas Smartbond(tm) MIPI DBI Host + +compatible: "renesas,smartbond-mipi-dbi" + +properties: + reg: + required: true + + interrupts: + required: true + + reset-gpios: + type: phandle-array + description: | + Reset GPIO pin. Used to reset the display during initialization. + + te-enable: + type: boolean + description: | + Boolean to indicate whether the tearing effect (TE) signal is available or not. + + te-inversion: + type: boolean + description: | + Boolean to apply an inversion on the TE signal that triggers the MIPI DBI controller. + + dma-prefetch: + type: string + enum: + - "no-prefetch" + - "prefetch-44-bytes" + - "prefetch-84-bytes" + - "prefetch-116-bytes" + - "prefetch-108-bytes" + description: | + Host controller will wait for at least the specified number of bytes before triggering + a single frame update. The prefetch mechanism should be enabled when frame buffer(s) + is stored into external storage mediums, e.g. PSRAM, that introduce comparable delays. + In such a case it might case that the controller runs into underrun conditions which + results in correpting the whole frame update. It's user's responsibility to ensure that + the selected value does not exceed frame's total size as otherwise the controller will + not be able to trigger the frame update. + + spi-dev: + type: phandle + description: | + SPI bus to use for display read operations. When this property is present, MIPI DBI read + operations will be exhibited by the driver. This is because, the LCDC IP block does not + support read functionality, natively.