From 40555f4505d6a8bb1c78ad81b381e1eac37a6950 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 11 Jul 2022 20:12:36 +0100 Subject: [PATCH 1/4] drivers: ssd16xx: Refactor activation Device activation always follows the same sequence, we first write the SSD16XX_CMD_UPDATE_CTRL_2 register followed by SSD16XX_CMD_MASTER_ACTIVATION. Create a helper function that performs both of these actions. Signed-off-by: Andreas Sandberg --- drivers/display/ssd16xx.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/display/ssd16xx.c b/drivers/display/ssd16xx.c index 8e80fb28693c4..990194d69dd3d 100644 --- a/drivers/display/ssd16xx.c +++ b/drivers/display/ssd16xx.c @@ -244,13 +244,11 @@ static inline int ssd16xx_set_ram_ptr(const struct device *dev, uint16_t x, return ssd16xx_write_cmd(dev, SSD16XX_CMD_RAM_YPOS_CNTR, tmp, len); } -static int ssd16xx_update_display(const struct device *dev) +static int ssd16xx_activate(const struct device *dev, uint8_t ctrl2) { - struct ssd16xx_data *data = dev->data; int err; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_CTRL2, - &data->update_cmd, 1); + err = ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_CTRL2, &ctrl2, 1); if (err < 0) { return err; } @@ -258,6 +256,13 @@ static int ssd16xx_update_display(const struct device *dev) return ssd16xx_write_cmd(dev, SSD16XX_CMD_MASTER_ACTIVATION, NULL, 0); } +static int ssd16xx_update_display(const struct device *dev) +{ + struct ssd16xx_data *data = dev->data; + + return ssd16xx_activate(dev, data->update_cmd); +} + static int ssd16xx_blanking_off(const struct device *dev) { struct ssd16xx_data *data = dev->data; @@ -602,13 +607,7 @@ static inline int ssd16xx_load_ws_from_otp(const struct device *dev) LOG_INF("Load default WS (25 degrees Celsius) from OTP"); - tmp[0] = SSD16XX_CTRL2_ENABLE_CLK; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_CTRL2, tmp, 1); - if (err < 0) { - return err; - } - - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_MASTER_ACTIVATION, NULL, 0); + err = ssd16xx_activate(dev, SSD16XX_CTRL2_ENABLE_CLK); if (err < 0) { return err; } @@ -620,13 +619,7 @@ static inline int ssd16xx_load_ws_from_otp(const struct device *dev) return err; } - tmp[0] = SSD16XX_CTRL2_DISABLE_CLK; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_CTRL2, tmp, 1); - if (err < 0) { - return err; - } - - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_MASTER_ACTIVATION, NULL, 0); + err = ssd16xx_activate(dev, SSD16XX_CTRL2_DISABLE_CLK); if (err < 0) { return err; } From 16a16c64833e3147873d3b4311f2a27d7a1dd65d Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Tue, 12 Jul 2022 21:26:51 +0100 Subject: [PATCH 2/4] drivers: ssd16xx: Add a helper for uint8 writes Many register writes only use 8 bits of data. A common pattern in the driver is to assign a constant to a temporary variable and write that to the device. Simplify this pattern by adding a helper function that writes an uint8 to a device. Signed-off-by: Andreas Sandberg --- drivers/display/ssd16xx.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/display/ssd16xx.c b/drivers/display/ssd16xx.c index 990194d69dd3d..4c1c0b7be97ba 100644 --- a/drivers/display/ssd16xx.c +++ b/drivers/display/ssd16xx.c @@ -117,6 +117,12 @@ static inline int ssd16xx_write_cmd(const struct device *dev, uint8_t cmd, return err; } +static inline int ssd16xx_write_uint8(const struct device *dev, uint8_t cmd, + uint8_t data) +{ + return ssd16xx_write_cmd(dev, cmd, &data, 1); +} + static inline int ssd16xx_read_cmd(const struct device *dev, uint8_t cmd, uint8_t *data, size_t len) { @@ -248,7 +254,7 @@ static int ssd16xx_activate(const struct device *dev, uint8_t ctrl2) { int err; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_CTRL2, &ctrl2, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_UPDATE_CTRL2, ctrl2); if (err < 0) { return err; } @@ -526,7 +532,6 @@ static int ssd16xx_clear_cntlr_mem(const struct device *dev, uint8_t ram_cmd, const struct ssd16xx_config *config = dev->config; uint16_t panel_h = config->height / EPD_PANEL_NUMOF_ROWS_PER_PAGE; uint16_t last_gate = config->width - 1; - uint8_t scan_mode = SSD16XX_DATA_ENTRY_XIYDY; uint8_t clear_page[64]; int err; @@ -538,7 +543,8 @@ static int ssd16xx_clear_cntlr_mem(const struct device *dev, uint8_t ram_cmd, panel_h += 1; } - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_ENTRY_MODE, &scan_mode, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_ENTRY_MODE, + SSD16XX_DATA_ENTRY_XIYDY); if (err < 0) { return err; } @@ -581,7 +587,6 @@ static inline int ssd16xx_load_ws_from_otp_tssv(const struct device *dev) { const struct ssd16xx_config *config = dev->config; struct ssd16xx_data *data = dev->data; - uint8_t tssv = config->tssv; int err; /* @@ -589,7 +594,8 @@ static inline int ssd16xx_load_ws_from_otp_tssv(const struct device *dev) * temperature sensor is connected to the controller. */ LOG_INF("Select and load WS from OTP"); - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_TSENSOR_SELECTION, &tssv, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_TSENSOR_SELECTION, + config->tssv); if (err == 0) { data->update_cmd |= SSD16XX_CTRL2_LOAD_LUT | SSD16XX_CTRL2_LOAD_TEMPERATURE; @@ -719,26 +725,25 @@ static int ssd16xx_controller_init(const struct device *dev) return err; } - tmp[0] = config->vcom; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_VCOM_VOLTAGE, tmp, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_VCOM_VOLTAGE, config->vcom); if (err < 0) { return err; } - tmp[0] = SSD16XX_VAL_DUMMY_LINE; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_DUMMY_LINE, tmp, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_DUMMY_LINE, + SSD16XX_VAL_DUMMY_LINE); if (err < 0) { return err; } - tmp[0] = SSD16XX_VAL_GATE_LWIDTH; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_GATE_LINE_WIDTH, tmp, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_GATE_LINE_WIDTH, + SSD16XX_VAL_GATE_LWIDTH); if (err < 0) { return err; } - tmp[0] = config->b_waveform; - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_BWF_CTRL, tmp, 1); + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_BWF_CTRL, + config->b_waveform); if (err < 0) { return err; } From d95f4057a1f096b92f3c3dd483cebe645ef1ea8e Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 11 Jul 2022 21:34:35 +0100 Subject: [PATCH 3/4] drivers: ssd16xx: Make voltage overrides optional The OTP in most SSD16xx-based displays normally contain default VCOM/GDV/SDV values. Make all of these optional in the device tree. Signed-off-by: Andreas Sandberg --- drivers/display/ssd16xx.c | 192 +++++++++++--------- dts/bindings/display/solomon,ssd16xxfb.yaml | 8 +- 2 files changed, 111 insertions(+), 89 deletions(-) diff --git a/drivers/display/ssd16xx.c b/drivers/display/ssd16xx.c index 4c1c0b7be97ba..ccda5aba275ba 100644 --- a/drivers/display/ssd16xx.c +++ b/drivers/display/ssd16xx.c @@ -45,21 +45,31 @@ struct ssd16xx_dt_array { uint8_t len; }; +struct ssd16xx_profile { + struct ssd16xx_dt_array lut; + struct ssd16xx_dt_array gdv; + struct ssd16xx_dt_array sdv; + uint8_t vcom; + uint8_t bwf; + + bool override_vcom; + bool override_bwf; +}; + struct ssd16xx_config { struct spi_dt_spec bus; struct gpio_dt_spec dc_gpio; struct gpio_dt_spec busy_gpio; struct gpio_dt_spec reset_gpio; - struct ssd16xx_dt_array lut_initial; - struct ssd16xx_dt_array lut_default; + struct ssd16xx_dt_array softstart; - struct ssd16xx_dt_array gdv; - struct ssd16xx_dt_array sdv; + + struct ssd16xx_profile profile_initial; + struct ssd16xx_dt_array lut_default; + bool orientation; uint16_t height; uint16_t width; - uint8_t vcom; - uint8_t b_waveform; uint8_t tssv; uint8_t pp_width_bits; uint8_t pp_height_bits; @@ -78,7 +88,7 @@ static inline void ssd16xx_busy_wait(const struct device *dev) } static inline int ssd16xx_write_cmd(const struct device *dev, uint8_t cmd, - uint8_t *data, size_t len) + const uint8_t *data, size_t len) { const struct ssd16xx_config *config = dev->config; struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)}; @@ -98,7 +108,7 @@ static inline int ssd16xx_write_cmd(const struct device *dev, uint8_t cmd, } if (data != NULL) { - buf.buf = data; + buf.buf = (void *)data; buf.len = len; err = gpio_pin_set_dt(&config->dc_gpio, 0); @@ -635,14 +645,19 @@ static inline int ssd16xx_load_ws_from_otp(const struct device *dev) return 0; } -static int ssd16xx_load_ws_initial(const struct device *dev) + +static int ssd16xx_load_lut(const struct device *dev, + const struct ssd16xx_dt_array *lut) { const struct ssd16xx_config *config = dev->config; + struct ssd16xx_data *data = dev->data; - if (config->lut_initial.len) { + if (lut && lut->len) { + LOG_DBG("Using user-provided LUT"); + /* Don't load the default LUT on the next refresh */ + data->update_cmd &= ~SSD16XX_CTRL2_LOAD_LUT; return ssd16xx_write_cmd(dev, SSD16XX_CMD_UPDATE_LUT, - config->lut_initial.data, - config->lut_initial.len); + lut->data, lut->len); } else { if (config->tssv) { return ssd16xx_load_ws_from_otp_tssv(dev); @@ -652,6 +667,55 @@ static int ssd16xx_load_ws_initial(const struct device *dev) } } +static int ssd16xx_load_profile(const struct device *dev, + const struct ssd16xx_profile *p) +{ + int err = 0; + + err = ssd16xx_load_lut(dev, &p->lut); + if (err < 0) { + return err; + } + + if (p->gdv.len) { + LOG_DBG("Setting GDV"); + err = ssd16xx_write_cmd(dev, SSD16XX_CMD_GDV_CTRL, + p->gdv.data, p->gdv.len); + if (err < 0) { + return err; + } + } + + if (p->sdv.len) { + LOG_DBG("Setting SDV"); + err = ssd16xx_write_cmd(dev, SSD16XX_CMD_SDV_CTRL, + p->sdv.data, p->sdv.len); + if (err < 0) { + return err; + } + } + + if (p->override_vcom) { + LOG_DBG("Setting VCOM"); + err = ssd16xx_write_cmd(dev, SSD16XX_CMD_VCOM_VOLTAGE, + &p->vcom, 1); + if (err < 0) { + return err; + } + } + + if (p->override_bwf) { + LOG_DBG("Setting BWF"); + err = ssd16xx_write_cmd(dev, SSD16XX_CMD_BWF_CTRL, + &p->bwf, 1); + if (err < 0) { + return err; + } + } + + return 0; +} + static int ssd16xx_load_ws_default(const struct device *dev) { const struct ssd16xx_config *config = dev->config; @@ -713,23 +777,6 @@ static int ssd16xx_controller_init(const struct device *dev) } } - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_GDV_CTRL, config->gdv.data, - config->gdv.len); - if (err < 0) { - return err; - } - - err = ssd16xx_write_cmd(dev, SSD16XX_CMD_SDV_CTRL, config->sdv.data, - config->sdv.len); - if (err < 0) { - return err; - } - - err = ssd16xx_write_uint8(dev, SSD16XX_CMD_VCOM_VOLTAGE, config->vcom); - if (err < 0) { - return err; - } - err = ssd16xx_write_uint8(dev, SSD16XX_CMD_DUMMY_LINE, SSD16XX_VAL_DUMMY_LINE); if (err < 0) { @@ -742,12 +789,6 @@ static int ssd16xx_controller_init(const struct device *dev) return err; } - err = ssd16xx_write_uint8(dev, SSD16XX_CMD_BWF_CTRL, - config->b_waveform); - if (err < 0) { - return err; - } - if (config->orientation == 1) { data->scan_mode = SSD16XX_DATA_ENTRY_XIYDY; } else { @@ -760,7 +801,7 @@ static int ssd16xx_controller_init(const struct device *dev) SSD16XX_CTRL2_DISABLE_ANALOG | SSD16XX_CTRL2_DISABLE_CLK); - err = ssd16xx_load_ws_initial(dev); + err = ssd16xx_load_profile(dev, &config->profile_initial); if (err < 0) { return err; } @@ -849,19 +890,6 @@ static struct display_driver_api ssd16xx_driver_api = { .set_orientation = ssd16xx_set_orientation, }; -#define LUT_INITIAL_DEFINE(n) \ - static uint8_t lut_initial_##n[] = DT_INST_PROP(n, lut_initial); -#define LUT_DEFAULT_DEFINE(n) \ - static uint8_t lut_default_##n[] = DT_INST_PROP(n, lut_default); -#define SOFTSTART_DEFINE(n) \ - static uint8_t softstart_##n[] = DT_INST_PROP(n, softstart); - -#define LUT_INITIAL_ASSIGN(n) \ - .lut_initial = { \ - .data = lut_initial_##n, \ - .len = sizeof(lut_initial_##n), \ - }, - #define LUT_DEFAULT_ASSIGN(n) \ .lut_default = { \ .data = lut_default_##n, \ @@ -874,33 +902,35 @@ static struct display_driver_api ssd16xx_driver_api = { .len = sizeof(softstart_##n), \ }, -#define CMD_ARRAY_DEFINE(n) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, lut_initial), \ - (LUT_INITIAL_DEFINE(n)), \ - ()) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, lut_default), \ - (LUT_DEFAULT_DEFINE(n)), \ - ()) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, softstart), \ - (SOFTSTART_DEFINE(n)), \ - ()) - -#define CMD_ARRAY_COND(n) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, lut_initial), \ - (LUT_INITIAL_ASSIGN(n)), \ - ()) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, lut_default), \ - (LUT_DEFAULT_ASSIGN(n)), \ - ()) \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(n, softstart), \ - (SOFTSTART_ASSIGN(n)), \ - ()) +#define SSD16XX_MAKE_INST_ARRAY_OPT(n, p) \ + static uint8_t data_ ## n ## _ ## p[] = DT_INST_PROP_OR(n, p, {}) + +#define SSD16XX_ASSIGN_ARRAY(n, p) \ + { \ + .data = data_ ## n ## _ ## p, \ + .len = sizeof(data_ ## n ## _ ## p), \ + } + +#define SSD16XX_INITIAL_PROFILE_DEFINE(n) \ + SSD16XX_MAKE_INST_ARRAY_OPT(n, lut_initial); \ + SSD16XX_MAKE_INST_ARRAY_OPT(n, gdv); \ + SSD16XX_MAKE_INST_ARRAY_OPT(n, sdv) + +#define SSD16XX_INITIAL_PROFILE(n) \ + { \ + .lut = SSD16XX_ASSIGN_ARRAY(n, lut_initial), \ + .gdv = SSD16XX_ASSIGN_ARRAY(n, gdv), \ + .sdv = SSD16XX_ASSIGN_ARRAY(n, sdv), \ + .vcom = DT_INST_PROP_OR(n, vcom, 0), \ + .override_vcom = DT_INST_NODE_HAS_PROP(n, vcom), \ + .bwf = DT_INST_PROP_OR(n, border_waveform, 0), \ + .override_bwf = DT_INST_NODE_HAS_PROP(n, border_waveform), \ + } #define SSD16XX_DEFINE(n) \ - static uint8_t gdv_##n[] = DT_INST_PROP(n, gdv); \ - static uint8_t sdv_##n[] = DT_INST_PROP(n, sdv); \ - \ - CMD_ARRAY_DEFINE(n) \ + SSD16XX_MAKE_INST_ARRAY_OPT(n, lut_default); \ + SSD16XX_MAKE_INST_ARRAY_OPT(n, softstart); \ + SSD16XX_INITIAL_PROFILE_DEFINE(n); \ \ static const struct ssd16xx_config ssd16xx_cfg_##n = { \ .bus = SPI_DT_SPEC_INST_GET(n, \ @@ -913,20 +943,12 @@ static struct display_driver_api ssd16xx_driver_api = { .height = DT_INST_PROP(n, height), \ .width = DT_INST_PROP(n, width), \ .orientation = DT_INST_PROP(n, orientation_flipped), \ - .vcom = DT_INST_PROP(n, vcom), \ .pp_width_bits = DT_INST_PROP(n, pp_width_bits), \ .pp_height_bits = DT_INST_PROP(n, pp_height_bits), \ - .b_waveform = DT_INST_PROP(n, border_waveform), \ - .gdv = { \ - .data = gdv_##n, \ - .len = sizeof(gdv_##n), \ - }, \ - .sdv = { \ - .data = sdv_##n, \ - .len = sizeof(sdv_##n), \ - }, \ .tssv = DT_INST_PROP_OR(n, tssv, 0), \ - CMD_ARRAY_COND(n) \ + .softstart = SSD16XX_ASSIGN_ARRAY(n, softstart), \ + .lut_default = SSD16XX_ASSIGN_ARRAY(n, lut_default), \ + .profile_initial = SSD16XX_INITIAL_PROFILE(n), \ }; \ \ static struct ssd16xx_data ssd16xx_data_##n; \ diff --git a/dts/bindings/display/solomon,ssd16xxfb.yaml b/dts/bindings/display/solomon,ssd16xxfb.yaml index 66be38c084abd..f6123d3a03a5c 100644 --- a/dts/bindings/display/solomon,ssd16xxfb.yaml +++ b/dts/bindings/display/solomon,ssd16xxfb.yaml @@ -20,22 +20,22 @@ properties: gdv: type: uint8-array - required: true + required: false description: Gate driving voltage values sdv: type: uint8-array - required: true + required: false description: Source driving voltage values vcom: type: int - required: true + required: false description: VCOM voltage border-waveform: type: int - required: true + required: false description: Border waveform softstart: From 8d6a18f5e85c8fe003a66253d8de8f293815081f Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Tue, 12 Jul 2022 21:06:55 +0100 Subject: [PATCH 4/4] drivers: ssd16xx: Make SSD1673 registers optional The SSD16xx driver currently hard-codes a couple of register overrides that aren't relevant or even correct for many devices. Make them optional device tree properties instead. Note that this changes the behavior for panels that expect SSD16XX_CMD_DUMMY_LINE and SSD16XX_CMD_GATE_LINE_WIDTH to be set by the driver. This fixes a bug where the incorrect value was written to all SSD16xx panels except for GDEH0213B1 and GDEH029A1. The overlay files for devices that need dummy line and gate line width to be specified have been updated as a part of this commit. Signed-off-by: Andreas Sandberg --- boards/arm/reel_board/reel_board.dts | 2 ++ boards/arm/reel_board/reel_board_v2.dts | 2 ++ .../waveshare_epaper_gdeh0154a07.overlay | 5 +-- .../waveshare_epaper_gdeh0213b1.overlay | 2 ++ .../waveshare_epaper_gdeh0213b72.overlay | 2 ++ .../waveshare_epaper_gdeh029a1.overlay | 2 ++ drivers/display/ssd16xx.c | 34 ++++++++++++++----- drivers/display/ssd16xx_regs.h | 4 --- dts/bindings/display/solomon,ssd16xxfb.yaml | 15 ++++++++ 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/boards/arm/reel_board/reel_board.dts b/boards/arm/reel_board/reel_board.dts index 6c533cbf59514..fbfd61ebf4c0c 100644 --- a/boards/arm/reel_board/reel_board.dts +++ b/boards/arm/reel_board/reel_board.dts @@ -72,6 +72,8 @@ sdv = [19]; vcom = <0xa8>; border-waveform = <0x71>; + dummy-line = <0x1a>; + gate-line-width = <0x08>; lut-initial = [ 22 55 AA 55 AA 55 AA 11 00 00 00 00 00 00 00 00 diff --git a/boards/arm/reel_board/reel_board_v2.dts b/boards/arm/reel_board/reel_board_v2.dts index 9e7f65d5ffafe..6e246adfd80ec 100644 --- a/boards/arm/reel_board/reel_board_v2.dts +++ b/boards/arm/reel_board/reel_board_v2.dts @@ -55,6 +55,8 @@ sdv = [41 a8 32]; vcom = <0x26>; border-waveform = <0x03>; + dummy-line = <0x30>; + gate-line-width = <0x0a>; lut-initial = [ /* * Waveform Composition diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0154a07.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0154a07.overlay index a3fd45d424a70..ae212022edf38 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0154a07.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0154a07.overlay @@ -25,10 +25,7 @@ dc-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */ busy-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */ - gdv = [00]; - sdv = [41 a8 32]; - vcom = <0x00>; - border-waveform = <0x05>; + border-waveform = <0x3c>; tssv = <0x80>; }; }; diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b1.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b1.overlay index b2bf667e5b5c5..6195cd64787e5 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b1.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b1.overlay @@ -29,6 +29,8 @@ sdv = [19]; vcom = <0xa8>; border-waveform = <0x71>; + dummy-line = <0x1a>; + gate-line-width = <0x08>; lut-initial = [ 22 55 AA 55 AA 55 AA 11 00 00 00 00 00 00 00 00 diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b72.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b72.overlay index 131cc847fc19b..87a2ef4474015 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b72.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh0213b72.overlay @@ -29,6 +29,8 @@ sdv = [41 a8 32]; vcom = <0x26>; border-waveform = <0x03>; + dummy-line = <0x30>; + gate-line-width = <0x0a>; lut-initial = [ 80 60 40 00 00 00 00 10 60 20 00 00 00 00 diff --git a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh029a1.overlay b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh029a1.overlay index 6095c8e097e31..6e065d0a827b7 100644 --- a/boards/shields/waveshare_epaper/waveshare_epaper_gdeh029a1.overlay +++ b/boards/shields/waveshare_epaper/waveshare_epaper_gdeh029a1.overlay @@ -30,6 +30,8 @@ vcom = <0xa8>; border-waveform = <0x33>; softstart = [d7 d6 9d]; + dummy-line = <0x1a>; + gate-line-width = <0x08>; lut-initial = [ 50 AA 55 AA 11 00 00 00 00 00 00 00 00 00 00 00 diff --git a/drivers/display/ssd16xx.c b/drivers/display/ssd16xx.c index ccda5aba275ba..e5817b8a86f8d 100644 --- a/drivers/display/ssd16xx.c +++ b/drivers/display/ssd16xx.c @@ -73,6 +73,12 @@ struct ssd16xx_config { uint8_t tssv; uint8_t pp_width_bits; uint8_t pp_height_bits; + + uint8_t dummy_line; + bool override_dummy_line; + + uint8_t gate_line_width; + bool override_gate_line_width; }; static inline void ssd16xx_busy_wait(const struct device *dev) @@ -777,16 +783,21 @@ static int ssd16xx_controller_init(const struct device *dev) } } - err = ssd16xx_write_uint8(dev, SSD16XX_CMD_DUMMY_LINE, - SSD16XX_VAL_DUMMY_LINE); - if (err < 0) { - return err; + if (config->override_dummy_line) { + tmp[0] = config->dummy_line; + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_DUMMY_LINE, + config->dummy_line); + if (err < 0) { + return err; + } } - err = ssd16xx_write_uint8(dev, SSD16XX_CMD_GATE_LINE_WIDTH, - SSD16XX_VAL_GATE_LWIDTH); - if (err < 0) { - return err; + if (config->override_gate_line_width) { + err = ssd16xx_write_uint8(dev, SSD16XX_CMD_GATE_LINE_WIDTH, + config->override_gate_line_width); + if (err < 0) { + return err; + } } if (config->orientation == 1) { @@ -949,6 +960,13 @@ static struct display_driver_api ssd16xx_driver_api = { .softstart = SSD16XX_ASSIGN_ARRAY(n, softstart), \ .lut_default = SSD16XX_ASSIGN_ARRAY(n, lut_default), \ .profile_initial = SSD16XX_INITIAL_PROFILE(n), \ + .dummy_line = DT_INST_PROP_OR(n, dummy_line, 0), \ + .override_dummy_line = \ + DT_INST_NODE_HAS_PROP(n, dummy_line), \ + .gate_line_width = \ + DT_INST_PROP_OR(n, gate_line_width, 0), \ + .override_gate_line_width = \ + DT_INST_NODE_HAS_PROP(n, gate_line_width), \ }; \ \ static struct ssd16xx_data ssd16xx_data_##n; \ diff --git a/drivers/display/ssd16xx_regs.h b/drivers/display/ssd16xx_regs.h index 2aaa8b015453c..900a824070570 100644 --- a/drivers/display/ssd16xx_regs.h +++ b/drivers/display/ssd16xx_regs.h @@ -80,10 +80,6 @@ #define SSD16XX_RAM_READ_CTRL_BLACK 0 #define SSD16XX_RAM_READ_CTRL_RED 1 -/* Default values */ -#define SSD16XX_VAL_DUMMY_LINE 0x1a -#define SSD16XX_VAL_GATE_LWIDTH 0x08 - /* time constants in ms */ #define SSD16XX_RESET_DELAY 1 #define SSD16XX_BUSY_DELAY 1 diff --git a/dts/bindings/display/solomon,ssd16xxfb.yaml b/dts/bindings/display/solomon,ssd16xxfb.yaml index f6123d3a03a5c..a15e623e339b4 100644 --- a/dts/bindings/display/solomon,ssd16xxfb.yaml +++ b/dts/bindings/display/solomon,ssd16xxfb.yaml @@ -78,6 +78,11 @@ properties: lut-initial: type: uint8-array required: false + description: | + Initial LUT used when initializing the device and performing + clearing the screen using a full refresh operation. The + default LUT will be loaded from OTP if this property isn't + defined. lut-default: type: uint8-array @@ -91,3 +96,13 @@ properties: Display controller can have integrated temperature sensor or an external temperature sensor is connected to the controller. The value selects which sensor should be used. + + dummy-line: + type: int + required: false + description: Dummy line period override. + + gate-line-width: + type: int + required: false + description: Gate line width override.