drivers: ssd1673: rename driver to ssd16xx

ssd1673 driver supports different controllers,
rename it to more generic ssd16xx.

Signed-off-by: Johann Fischer <j.fischer@phytec.de>
This commit is contained in:
Johann Fischer 2019-07-03 23:40:38 +02:00 committed by Anas Nashif
commit fc57ea8d3c
27 changed files with 797 additions and 793 deletions

View file

@ -117,9 +117,9 @@
miso-pin = <21>; miso-pin = <21>;
cs-gpios = <&gpio0 17 0>; cs-gpios = <&gpio0 17 0>;
ssd1673fb@0 { ssd16xxfb@0 {
compatible = "solomon,ssd1673fb", "gd,gde0213b1"; compatible = "solomon,ssd16xxfb", "gd,gde0213b1";
label = "SSD1673"; label = "SSD16XX";
spi-max-frequency = <4000000>; spi-max-frequency = <4000000>;
reg = <0>; reg = <0>;
width = <250>; width = <250>;

View file

@ -3,7 +3,7 @@
zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF display_mcux_elcdif.c) zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF display_mcux_elcdif.c)
zephyr_sources_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb.c) zephyr_sources_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb.c)
zephyr_sources_ifdef(CONFIG_SSD1306 ssd1306.c) zephyr_sources_ifdef(CONFIG_SSD1306 ssd1306.c)
zephyr_sources_ifdef(CONFIG_SSD1673 ssd1673.c) zephyr_sources_ifdef(CONFIG_SSD16XX ssd16xx.c)
zephyr_sources_ifdef(CONFIG_SDL_DISPLAY display_sdl.c) zephyr_sources_ifdef(CONFIG_SDL_DISPLAY display_sdl.c)
zephyr_sources_ifdef(CONFIG_DUMMY_DISPLAY display_dummy.c) zephyr_sources_ifdef(CONFIG_DUMMY_DISPLAY display_dummy.c)
zephyr_sources_ifdef(CONFIG_FRAMEBUF_DISPLAY display_framebuf.c) zephyr_sources_ifdef(CONFIG_FRAMEBUF_DISPLAY display_framebuf.c)

View file

@ -23,7 +23,7 @@ source "drivers/display/Kconfig.microbit"
source "drivers/display/Kconfig.ili9340" source "drivers/display/Kconfig.ili9340"
source "drivers/display/Kconfig.sdl" source "drivers/display/Kconfig.sdl"
source "drivers/display/Kconfig.ssd1306" source "drivers/display/Kconfig.ssd1306"
source "drivers/display/Kconfig.ssd1673" source "drivers/display/Kconfig.ssd16xx"
source "drivers/display/Kconfig.dummy" source "drivers/display/Kconfig.dummy"
config FRAMEBUF_DISPLAY config FRAMEBUF_DISPLAY

View file

@ -19,7 +19,7 @@ config SSD1306_DEFAULT_CONTRAST
default 128 default 128
range 0 255 range 0 255
help help
SSD1673 default contrast. SSD16XX default contrast.
choice choice
prompt "Display controller type" prompt "Display controller type"

View file

@ -1,28 +0,0 @@
# Kconfig - SSD1673 display controller configuration options
#
# Copyright (c) 2018 Phytec Messtechnik GmbH
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig SSD1673
bool "SSD1673 display driver"
depends on SPI
help
Enable driver for SSD1673 display driver.
if SSD1673
choice
prompt "EPD display"
default SSD1673_EPD_GDE0213B1
help
Specify the type of EPD connected to the SSD1673 controller.
config SSD1673_EPD_GDE0213B1
bool "GDE0213B1 2.13\""
endchoice
endif #SSD1673

View file

@ -0,0 +1,28 @@
# Kconfig - SSD16XX display controller configuration options
#
# Copyright (c) 2018 Phytec Messtechnik GmbH
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig SSD16XX
bool "SSD16XX display driver"
depends on SPI
help
Enable driver for SSD16XX display driver.
if SSD16XX
choice
prompt "EPD display"
default SSD16XX_EPD_GDE0213B1
help
Specify the type of EPD connected to the SSD16XX controller.
config SSD16XX_EPD_GDE0213B1
bool "GDE0213B1 2.13\""
endchoice
endif #SSD16XX

View file

@ -1,658 +0,0 @@
/*
* Copyright (c) 2018 PHYTEC Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_DISPLAY_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(ssd1673);
#include <string.h>
#include <device.h>
#include <drivers/display.h>
#include <init.h>
#include <drivers/gpio.h>
#include <drivers/spi.h>
#include <sys/byteorder.h>
#include "ssd1673_regs.h"
#include <display/cfb.h>
#define EPD_PANEL_WIDTH DT_INST_0_SOLOMON_SSD1673FB_WIDTH
#define EPD_PANEL_HEIGHT DT_INST_0_SOLOMON_SSD1673FB_HEIGHT
#define EPD_PANEL_NUMOF_COLUMS EPD_PANEL_WIDTH
#define EPD_PANEL_NUMOF_ROWS_PER_PAGE 8
#define EPD_PANEL_NUMOF_PAGES (EPD_PANEL_HEIGHT / \
EPD_PANEL_NUMOF_ROWS_PER_PAGE)
#define SSD1673_PANEL_FIRST_PAGE 0
#define SSD1673_PANEL_LAST_PAGE (EPD_PANEL_NUMOF_PAGES - 1)
#define SSD1673_PANEL_FIRST_GATE 0
#define SSD1673_PANEL_LAST_GATE (EPD_PANEL_NUMOF_COLUMS - 1)
#define SSD1673_PIXELS_PER_BYTE 8
struct ssd1673_data {
struct device *reset;
struct device *dc;
struct device *busy;
struct device *spi_dev;
struct spi_config spi_config;
#if defined(DT_INST_0_SOLOMON_SSD1673FB_CS_GPIOS_CONTROLLER)
struct spi_cs_control cs_ctrl;
#endif
u8_t scan_mode;
};
#if defined(DT_GD_GDE0213B1_0)
static u8_t ssd1673_lut_initial[] = {
0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x01, 0x00, 0x00, 0x00, 0x00
};
static u8_t ssd1673_lut_default[] = {
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};
#elif defined(DT_GD_GDE029A1_0)
static u8_t ssd1673_lut_initial[] = {
0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static u8_t ssd1673_lut_default[] = {
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#elif defined(DT_HINK_E0154A05_0)
static u8_t ssd1673_lut_initial[] = {
0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88,
0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51,
0x35, 0x51, 0x51, 0x19, 0x01, 0x00
};
static u8_t ssd1673_lut_default[] = {
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#else
#error "No waveform look up table (LUT) selected!"
#endif
static inline int ssd1673_write_cmd(struct ssd1673_data *driver,
u8_t cmd, u8_t *data, size_t len)
{
int err;
struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)};
struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_PIN, 0);
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
if (data != NULL) {
buf.buf = data;
buf.len = len;
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_PIN, 1);
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
}
return 0;
}
static inline void ssd1673_busy_wait(struct ssd1673_data *driver)
{
u32_t val = 0U;
gpio_pin_read(driver->busy, DT_INST_0_SOLOMON_SSD1673FB_BUSY_GPIOS_PIN, &val);
while (val) {
k_sleep(SSD1673_BUSY_DELAY);
gpio_pin_read(driver->busy, DT_INST_0_SOLOMON_SSD1673FB_BUSY_GPIOS_PIN, &val);
}
}
static inline size_t push_x_param(u8_t *data, u16_t x)
{
#if DT_INST_0_SOLOMON_SSD1673FB_PP_WIDTH_BITS == 8
data[0] = (u8_t)x;
return 1;
#elif DT_INST_0_SOLOMON_SSD1673FB_PP_WIDTH_BITS == 16
sys_put_le16(sys_cpu_to_le16(x), data);
return 2;
#else
#error Unsupported DT_INST_0_SOLOMON_SSD1673FB_PP_WIDTH_BITS value
#endif
}
static inline size_t push_y_param(u8_t *data, u16_t y)
{
#if DT_INST_0_SOLOMON_SSD1673FB_PP_HEIGHT_BITS == 8
data[0] = (u8_t)y;
return 1;
#elif DT_INST_0_SOLOMON_SSD1673FB_PP_HEIGHT_BITS == 16
sys_put_le16(sys_cpu_to_le16(y), data);
return 2;
#else
#error Unsupported DT_INST_0_SOLOMON_SSD1673FB_PP_HEIGHT_BITS value
#endif
}
static inline int ssd1673_set_ram_param(struct ssd1673_data *driver,
u16_t sx, u16_t ex, u16_t sy, u16_t ey)
{
int err;
u8_t tmp[4];
size_t len;
len = push_x_param(tmp, sx);
len += push_x_param(tmp + len, ex);
err = ssd1673_write_cmd(driver, SSD1673_CMD_RAM_XPOS_CTRL, tmp, len);
if (err < 0) {
return err;
}
len = push_y_param(tmp, sy);
len += push_y_param(tmp + len, ey);
err = ssd1673_write_cmd(driver, SSD1673_CMD_RAM_YPOS_CTRL, tmp, len);
if (err < 0) {
return err;
}
return 0;
}
static inline int ssd1673_set_ram_ptr(struct ssd1673_data *driver,
u16_t x, u16_t y)
{
int err;
u8_t tmp[2];
size_t len;
len = push_x_param(tmp, x);
err = ssd1673_write_cmd(driver, SSD1673_CMD_RAM_XPOS_CNTR, tmp, len);
if (err < 0) {
return err;
}
len = push_y_param(tmp, y);
return ssd1673_write_cmd(driver, SSD1673_CMD_RAM_YPOS_CNTR, tmp, len);
}
static void ssd1673_set_orientation_internall(struct ssd1673_data *driver)
{
#if DT_INST_0_SOLOMON_SSD1673FB_ORIENTATION_FLIPPED == 1
driver->scan_mode = SSD1673_DATA_ENTRY_XIYDY;
#else
driver->scan_mode = SSD1673_DATA_ENTRY_XDYIY;
#endif
}
int ssd1673_resume(const struct device *dev)
{
struct ssd1673_data *driver = dev->driver_data;
u8_t tmp;
/*
* Uncomment for voltage measurement
* tmp = SSD1673_CTRL2_ENABLE_CLK;
* ssd1673_write_cmd(SSD1673_CMD_UPDATE_CTRL2, &tmp, sizeof(tmp));
* ssd1673_write_cmd(SSD1673_CMD_MASTER_ACTIVATION, NULL, 0);
*/
tmp = SSD1673_SLEEP_MODE_PON;
return ssd1673_write_cmd(driver, SSD1673_CMD_SLEEP_MODE,
&tmp, sizeof(tmp));
}
static int ssd1673_suspend(const struct device *dev)
{
struct ssd1673_data *driver = dev->driver_data;
u8_t tmp = SSD1673_SLEEP_MODE_DSM;
return ssd1673_write_cmd(driver, SSD1673_CMD_SLEEP_MODE,
&tmp, sizeof(tmp));
}
static int ssd1673_update_display(const struct device *dev)
{
struct ssd1673_data *driver = dev->driver_data;
u8_t tmp;
int err;
tmp = SSD1673_CTRL1_INITIAL_UPDATE_LH;
err = ssd1673_write_cmd(driver, SSD1673_CMD_UPDATE_CTRL1,
&tmp, sizeof(tmp));
if (err < 0) {
return err;
}
tmp = (SSD1673_CTRL2_ENABLE_CLK |
SSD1673_CTRL2_ENABLE_ANALOG |
SSD1673_CTRL2_TO_PATTERN |
SSD1673_CTRL2_DISABLE_ANALOG |
SSD1673_CTRL2_DISABLE_CLK);
err = ssd1673_write_cmd(driver, SSD1673_CMD_UPDATE_CTRL2, &tmp,
sizeof(tmp));
if (err < 0) {
return err;
}
return ssd1673_write_cmd(driver, SSD1673_CMD_MASTER_ACTIVATION,
NULL, 0);
}
static int ssd1673_write(const struct device *dev, const u16_t x,
const u16_t y,
const struct display_buffer_descriptor *desc,
const void *buf)
{
struct ssd1673_data *driver = dev->driver_data;
int err;
u16_t x_start;
u16_t x_end;
u16_t y_start;
u16_t y_end;
if (desc->pitch < desc->width) {
LOG_ERR("Pitch is smaller than width");
return -EINVAL;
}
if (buf == NULL || desc->buf_size == 0U) {
LOG_ERR("Display buffer is not available");
return -EINVAL;
}
if (desc->pitch > desc->width) {
LOG_ERR("Unsupported mode");
return -ENOTSUP;
}
if ((y + desc->height) > EPD_PANEL_HEIGHT) {
LOG_ERR("Buffer out of bounds (height)");
return -EINVAL;
}
if ((x + desc->width) > EPD_PANEL_WIDTH) {
LOG_ERR("Buffer out of bounds (width)");
return -EINVAL;
}
if ((desc->height % EPD_PANEL_NUMOF_ROWS_PER_PAGE) != 0U) {
LOG_ERR("Buffer height not multiple of %d",
EPD_PANEL_NUMOF_ROWS_PER_PAGE);
return -EINVAL;
}
if ((y % EPD_PANEL_NUMOF_ROWS_PER_PAGE) != 0U) {
LOG_ERR("Y coordinate not multiple of %d",
EPD_PANEL_NUMOF_ROWS_PER_PAGE);
return -EINVAL;
}
switch (driver->scan_mode) {
case SSD1673_DATA_ENTRY_XIYDY:
x_start = y / SSD1673_PIXELS_PER_BYTE;
x_end = (y + desc->height - 1) / SSD1673_PIXELS_PER_BYTE;
y_start = (x + desc->width - 1);
y_end = x;
break;
case SSD1673_DATA_ENTRY_XDYIY:
x_start = (EPD_PANEL_HEIGHT - 1 - y) / SSD1673_PIXELS_PER_BYTE;
x_end = (EPD_PANEL_HEIGHT - 1 - (y + desc->height - 1)) /
SSD1673_PIXELS_PER_BYTE;
y_start = x;
y_end = (x + desc->width - 1);
break;
default:
return -EINVAL;
}
ssd1673_busy_wait(driver);
err = ssd1673_write_cmd(driver, SSD1673_CMD_ENTRY_MODE,
&driver->scan_mode, sizeof(driver->scan_mode));
if (err < 0) {
return err;
}
err = ssd1673_set_ram_param(driver, x_start, x_end, y_start, y_end);
if (err < 0) {
return err;
}
err = ssd1673_set_ram_ptr(driver, x_start, y_start);
if (err < 0) {
return err;
}
err = ssd1673_write_cmd(driver, SSD1673_CMD_WRITE_RAM, (u8_t *)buf,
desc->buf_size);
if (err < 0) {
return err;
}
return ssd1673_update_display(dev);
}
static int ssd1673_read(const struct device *dev, const u16_t x,
const u16_t y,
const struct display_buffer_descriptor *desc,
void *buf)
{
LOG_ERR("not supported");
return -ENOTSUP;
}
static void *ssd1673_get_framebuffer(const struct device *dev)
{
LOG_ERR("not supported");
return NULL;
}
static int ssd1673_set_brightness(const struct device *dev,
const u8_t brightness)
{
LOG_WRN("not supported");
return -ENOTSUP;
}
static int ssd1673_set_contrast(const struct device *dev, u8_t contrast)
{
LOG_WRN("not supported");
return -ENOTSUP;
}
static void ssd1673_get_capabilities(const struct device *dev,
struct display_capabilities *caps)
{
memset(caps, 0, sizeof(struct display_capabilities));
caps->x_resolution = EPD_PANEL_WIDTH;
caps->y_resolution = EPD_PANEL_HEIGHT;
caps->supported_pixel_formats = PIXEL_FORMAT_MONO10;
caps->current_pixel_format = PIXEL_FORMAT_MONO10;
caps->screen_info = SCREEN_INFO_MONO_VTILED |
SCREEN_INFO_MONO_MSB_FIRST |
SCREEN_INFO_EPD |
SCREEN_INFO_DOUBLE_BUFFER;
}
static int ssd1673_set_orientation(const struct device *dev,
const enum display_orientation
orientation)
{
LOG_ERR("Unsupported");
return -ENOTSUP;
}
static int ssd1673_set_pixel_format(const struct device *dev,
const enum display_pixel_format pf)
{
if (pf == PIXEL_FORMAT_MONO10) {
return 0;
}
LOG_ERR("not supported");
return -ENOTSUP;
}
static int ssd1673_clear_and_write_buffer(struct device *dev)
{
int err;
u8_t clear_page[EPD_PANEL_WIDTH];
u8_t page;
struct spi_buf sbuf;
struct spi_buf_set buf_set = {.buffers = &sbuf, .count = 1};
struct ssd1673_data *driver = dev->driver_data;
u8_t tmp;
tmp = SSD1673_DATA_ENTRY_XIYDY;
err = ssd1673_write_cmd(driver, SSD1673_CMD_ENTRY_MODE, &tmp, 1);
if (err < 0) {
return err;
}
err = ssd1673_set_ram_param(driver, SSD1673_PANEL_FIRST_PAGE,
SSD1673_PANEL_LAST_PAGE + 1,
SSD1673_PANEL_LAST_GATE,
SSD1673_PANEL_FIRST_GATE);
if (err < 0) {
return err;
}
err = ssd1673_set_ram_ptr(driver, SSD1673_PANEL_FIRST_PAGE,
SSD1673_PANEL_LAST_GATE);
if (err < 0) {
return err;
}
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_PIN, 0);
tmp = SSD1673_CMD_WRITE_RAM;
sbuf.buf = &tmp;
sbuf.len = 1;
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_PIN, 1);
memset(clear_page, 0xff, sizeof(clear_page));
sbuf.buf = clear_page;
sbuf.len = sizeof(clear_page);
for (page = 0U; page <= (SSD1673_PANEL_LAST_PAGE + 1); ++page) {
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
}
return ssd1673_update_display(dev);
}
static int ssd1673_controller_init(struct device *dev)
{
int err;
u8_t tmp[3];
size_t len;
struct ssd1673_data *driver = dev->driver_data;
LOG_DBG("");
gpio_pin_write(driver->reset, DT_INST_0_SOLOMON_SSD1673FB_RESET_GPIOS_PIN, 0);
k_sleep(SSD1673_RESET_DELAY);
gpio_pin_write(driver->reset, DT_INST_0_SOLOMON_SSD1673FB_RESET_GPIOS_PIN, 1);
k_sleep(SSD1673_RESET_DELAY);
ssd1673_busy_wait(driver);
err = ssd1673_write_cmd(driver, SSD1673_CMD_SW_RESET, NULL, 0);
if (err < 0) {
return err;
}
ssd1673_busy_wait(driver);
len = push_y_param(tmp, SSD1673_PANEL_LAST_GATE);
tmp[len++] = 0U;
err = ssd1673_write_cmd(driver, SSD1673_CMD_GDO_CTRL, tmp, len);
if (err < 0) {
return err;
}
#if defined(DT_INST_0_SOLOMON_SSD1673FB_SOFTSTART_1)
tmp[0] = DT_INST_0_SOLOMON_SSD1673FB_SOFTSTART_1;
tmp[1] = DT_INST_0_SOLOMON_SSD1673FB_SOFTSTART_2;
tmp[2] = DT_INST_0_SOLOMON_SSD1673FB_SOFTSTART_3;
err = ssd1673_write_cmd(driver, SSD1673_CMD_SOFTSTART, tmp, 3);
if (err < 0) {
return err;
}
#endif
tmp[0] = DT_INST_0_SOLOMON_SSD1673FB_GDV_A;
#if defined(DT_INST_0_SOLOMON_SSD1673FB_GDV_B)
tmp[1] = DT_INST_0_SOLOMON_SSD1673FB_GDV_B;
err = ssd1673_write_cmd(driver, SSD1673_CMD_GDV_CTRL, tmp, 2);
#else
err = ssd1673_write_cmd(driver, SSD1673_CMD_GDV_CTRL, tmp, 1);
#endif
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD1673FB_SDV;
err = ssd1673_write_cmd(driver, SSD1673_CMD_SDV_CTRL, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD1673FB_VCOM;
err = ssd1673_write_cmd(driver, SSD1673_CMD_VCOM_VOLTAGE, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = SSD1673_VAL_DUMMY_LINE;
err = ssd1673_write_cmd(driver, SSD1673_CMD_DUMMY_LINE, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = SSD1673_VAL_GATE_LWIDTH;
err = ssd1673_write_cmd(driver, SSD1673_CMD_GATE_LINE_WIDTH, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD1673FB_BORDER_WAVEFORM;
err = ssd1673_write_cmd(driver, SSD1673_CMD_BWF_CTRL, tmp, 1);
if (err < 0) {
return err;
}
ssd1673_set_orientation_internall(driver);
err = ssd1673_write_cmd(driver, SSD1673_CMD_UPDATE_LUT,
ssd1673_lut_initial,
sizeof(ssd1673_lut_initial));
if (err < 0) {
return err;
}
err = ssd1673_clear_and_write_buffer(dev);
if (err < 0) {
return err;
}
ssd1673_busy_wait(driver);
err = ssd1673_write_cmd(driver, SSD1673_CMD_UPDATE_LUT,
ssd1673_lut_default,
sizeof(ssd1673_lut_default));
if (err < 0) {
return err;
}
return ssd1673_clear_and_write_buffer(dev);
}
static int ssd1673_init(struct device *dev)
{
struct ssd1673_data *driver = dev->driver_data;
LOG_DBG("");
driver->spi_dev = device_get_binding(DT_INST_0_SOLOMON_SSD1673FB_BUS_NAME);
if (driver->spi_dev == NULL) {
LOG_ERR("Could not get SPI device for SSD1673");
return -EIO;
}
driver->spi_config.frequency = DT_INST_0_SOLOMON_SSD1673FB_SPI_MAX_FREQUENCY;
driver->spi_config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8);
driver->spi_config.slave = DT_INST_0_SOLOMON_SSD1673FB_BASE_ADDRESS;
driver->spi_config.cs = NULL;
driver->reset = device_get_binding(DT_INST_0_SOLOMON_SSD1673FB_RESET_GPIOS_CONTROLLER);
if (driver->reset == NULL) {
LOG_ERR("Could not get GPIO port for SSD1673 reset");
return -EIO;
}
gpio_pin_configure(driver->reset, DT_INST_0_SOLOMON_SSD1673FB_RESET_GPIOS_PIN,
GPIO_DIR_OUT);
driver->dc = device_get_binding(DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_CONTROLLER);
if (driver->dc == NULL) {
LOG_ERR("Could not get GPIO port for SSD1673 DC signal");
return -EIO;
}
gpio_pin_configure(driver->dc, DT_INST_0_SOLOMON_SSD1673FB_DC_GPIOS_PIN,
GPIO_DIR_OUT);
driver->busy = device_get_binding(DT_INST_0_SOLOMON_SSD1673FB_BUSY_GPIOS_CONTROLLER);
if (driver->busy == NULL) {
LOG_ERR("Could not get GPIO port for SSD1673 busy signal");
return -EIO;
}
gpio_pin_configure(driver->busy, DT_INST_0_SOLOMON_SSD1673FB_BUSY_GPIOS_PIN,
GPIO_DIR_IN);
#if defined(DT_INST_0_SOLOMON_SSD1673FB_CS_GPIOS_CONTROLLER)
driver->cs_ctrl.gpio_dev = device_get_binding(
DT_INST_0_SOLOMON_SSD1673FB_CS_GPIOS_CONTROLLER);
if (!driver->cs_ctrl.gpio_dev) {
LOG_ERR("Unable to get SPI GPIO CS device");
return -EIO;
}
driver->cs_ctrl.gpio_pin = DT_INST_0_SOLOMON_SSD1673FB_CS_GPIOS_PIN;
driver->cs_ctrl.delay = 0U;
driver->spi_config.cs = &driver->cs_ctrl;
#endif
return ssd1673_controller_init(dev);
}
static struct ssd1673_data ssd1673_driver;
static struct display_driver_api ssd1673_driver_api = {
.blanking_on = ssd1673_resume,
.blanking_off = ssd1673_suspend,
.write = ssd1673_write,
.read = ssd1673_read,
.get_framebuffer = ssd1673_get_framebuffer,
.set_brightness = ssd1673_set_brightness,
.set_contrast = ssd1673_set_contrast,
.get_capabilities = ssd1673_get_capabilities,
.set_pixel_format = ssd1673_set_pixel_format,
.set_orientation = ssd1673_set_orientation,
};
DEVICE_AND_API_INIT(ssd1673, DT_INST_0_SOLOMON_SSD1673FB_LABEL, ssd1673_init,
&ssd1673_driver, NULL,
POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY,
&ssd1673_driver_api);

View file

@ -1,77 +0,0 @@
/* ssd1673_regs.h - Registers definition for SSD1673 controller */
/*
* Copyright (c) 2018 PHYTEC Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SSD1673_REGS_H__
#define __SSD1673_REGS_H__
#define SSD1673_CMD_GDO_CTRL 0x01
#define SSD1673_CMD_GDV_CTRL 0x03
#define SSD1673_CMD_SDV_CTRL 0x04
#define SSD1673_CMD_SOFTSTART 0x0c
#define SSD1673_CMD_GSCAN_START 0x0f
#define SSD1673_CMD_SLEEP_MODE 0x10
#define SSD1673_CMD_ENTRY_MODE 0x11
#define SSD1673_CMD_SW_RESET 0x12
#define SSD1673_CMD_TSENS_CTRL 0x1a
#define SSD1673_CMD_MASTER_ACTIVATION 0x20
#define SSD1673_CMD_UPDATE_CTRL1 0x21
#define SSD1673_CMD_UPDATE_CTRL2 0x22
#define SSD1673_CMD_WRITE_RAM 0x24
#define SSD1673_CMD_VCOM_SENSE 0x28
#define SSD1673_CMD_VCOM_SENSE_DURATON 0x29
#define SSD1673_CMD_PRGM_VCOM_OTP 0x2a
#define SSD1673_CMD_VCOM_VOLTAGE 0x2c
#define SSD1673_CMD_PRGM_WS_OTP 0x30
#define SSD1673_CMD_UPDATE_LUT 0x32
#define SSD1673_CMD_PRGM_OTP_SELECTION 0x36
#define SSD1673_CMD_OTP_SELECTION_CTRL 0x37
#define SSD1673_CMD_DUMMY_LINE 0x3a
#define SSD1673_CMD_GATE_LINE_WIDTH 0x3b
#define SSD1673_CMD_BWF_CTRL 0x3c
#define SSD1673_CMD_RAM_XPOS_CTRL 0x44
#define SSD1673_CMD_RAM_YPOS_CTRL 0x45
#define SSD1673_CMD_RAM_XPOS_CNTR 0x4e
#define SSD1673_CMD_RAM_YPOS_CNTR 0x4f
/* Data entry sequence modes */
#define SSD1673_DATA_ENTRY_MASK 0x07
#define SSD1673_DATA_ENTRY_XDYDX 0x00
#define SSD1673_DATA_ENTRY_XIYDX 0x01
#define SSD1673_DATA_ENTRY_XDYIX 0x02
#define SSD1673_DATA_ENTRY_XIYIX 0x03
#define SSD1673_DATA_ENTRY_XDYDY 0x04
#define SSD1673_DATA_ENTRY_XIYDY 0x05
#define SSD1673_DATA_ENTRY_XDYIY 0x06
#define SSD1673_DATA_ENTRY_XIYIY 0x07
/* Options for display update */
#define SSD1673_CTRL1_INITIAL_UPDATE_LL 0x00
#define SSD1673_CTRL1_INITIAL_UPDATE_LH 0x01
#define SSD1673_CTRL1_INITIAL_UPDATE_HL 0x02
#define SSD1673_CTRL1_INITIAL_UPDATE_HH 0x03
/* Options for display update sequence */
#define SSD1673_CTRL2_ENABLE_CLK 0x80
#define SSD1673_CTRL2_ENABLE_ANALOG 0x40
#define SSD1673_CTRL2_TO_INITIAL 0x08
#define SSD1673_CTRL2_TO_PATTERN 0x04
#define SSD1673_CTRL2_DISABLE_ANALOG 0x02
#define SSD1673_CTRL2_DISABLE_CLK 0x01
#define SSD1673_SLEEP_MODE_DSM 0x01
#define SSD1673_SLEEP_MODE_PON 0x00
/* Default values */
#define SSD1673_VAL_DUMMY_LINE 0x1a
#define SSD1673_VAL_GATE_LWIDTH 0x08
/* time constants in ms */
#define SSD1673_RESET_DELAY 1
#define SSD1673_BUSY_DELAY 1
#endif /* __SSD1673_REGS_H__ */

662
drivers/display/ssd16xx.c Normal file
View file

@ -0,0 +1,662 @@
/*
* Copyright (c) 2018 PHYTEC Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_DISPLAY_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(ssd16xx);
#include <string.h>
#include <device.h>
#include <drivers/display.h>
#include <init.h>
#include <drivers/gpio.h>
#include <drivers/spi.h>
#include <sys/byteorder.h>
#include "ssd16xx_regs.h"
#include <display/cfb.h>
/**
* SSD1673, SSD1608 compatible EPD controller driver.
*/
#define EPD_PANEL_WIDTH DT_INST_0_SOLOMON_SSD16XXFB_WIDTH
#define EPD_PANEL_HEIGHT DT_INST_0_SOLOMON_SSD16XXFB_HEIGHT
#define EPD_PANEL_NUMOF_COLUMS EPD_PANEL_WIDTH
#define EPD_PANEL_NUMOF_ROWS_PER_PAGE 8
#define EPD_PANEL_NUMOF_PAGES (EPD_PANEL_HEIGHT / \
EPD_PANEL_NUMOF_ROWS_PER_PAGE)
#define SSD16XX_PANEL_FIRST_PAGE 0
#define SSD16XX_PANEL_LAST_PAGE (EPD_PANEL_NUMOF_PAGES - 1)
#define SSD16XX_PANEL_FIRST_GATE 0
#define SSD16XX_PANEL_LAST_GATE (EPD_PANEL_NUMOF_COLUMS - 1)
#define SSD16XX_PIXELS_PER_BYTE 8
struct ssd16xx_data {
struct device *reset;
struct device *dc;
struct device *busy;
struct device *spi_dev;
struct spi_config spi_config;
#if defined(DT_INST_0_SOLOMON_SSD16XXFB_CS_GPIOS_CONTROLLER)
struct spi_cs_control cs_ctrl;
#endif
u8_t scan_mode;
};
#if defined(DT_GD_GDE0213B1_0)
static u8_t ssd16xx_lut_initial[] = {
0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
0x01, 0x00, 0x00, 0x00, 0x00
};
static u8_t ssd16xx_lut_default[] = {
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};
#elif defined(DT_GD_GDE029A1_0)
static u8_t ssd16xx_lut_initial[] = {
0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static u8_t ssd16xx_lut_default[] = {
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#elif defined(DT_HINK_E0154A05_0)
static u8_t ssd16xx_lut_initial[] = {
0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88,
0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51,
0x35, 0x51, 0x51, 0x19, 0x01, 0x00
};
static u8_t ssd16xx_lut_default[] = {
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#else
#error "No waveform look up table (LUT) selected!"
#endif
static inline int ssd16xx_write_cmd(struct ssd16xx_data *driver,
u8_t cmd, u8_t *data, size_t len)
{
int err;
struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)};
struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_PIN, 0);
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
if (data != NULL) {
buf.buf = data;
buf.len = len;
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_PIN, 1);
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
}
return 0;
}
static inline void ssd16xx_busy_wait(struct ssd16xx_data *driver)
{
u32_t val = 0U;
gpio_pin_read(driver->busy, DT_INST_0_SOLOMON_SSD16XXFB_BUSY_GPIOS_PIN, &val);
while (val) {
k_sleep(SSD16XX_BUSY_DELAY);
gpio_pin_read(driver->busy, DT_INST_0_SOLOMON_SSD16XXFB_BUSY_GPIOS_PIN, &val);
}
}
static inline size_t push_x_param(u8_t *data, u16_t x)
{
#if DT_INST_0_SOLOMON_SSD16XXFB_PP_WIDTH_BITS == 8
data[0] = (u8_t)x;
return 1;
#elif DT_INST_0_SOLOMON_SSD16XXFB_PP_WIDTH_BITS == 16
sys_put_le16(sys_cpu_to_le16(x), data);
return 2;
#else
#error Unsupported DT_INST_0_SOLOMON_SSD16XXFB_PP_WIDTH_BITS value
#endif
}
static inline size_t push_y_param(u8_t *data, u16_t y)
{
#if DT_INST_0_SOLOMON_SSD16XXFB_PP_HEIGHT_BITS == 8
data[0] = (u8_t)y;
return 1;
#elif DT_INST_0_SOLOMON_SSD16XXFB_PP_HEIGHT_BITS == 16
sys_put_le16(sys_cpu_to_le16(y), data);
return 2;
#else
#error Unsupported DT_INST_0_SOLOMON_SSD16XXFB_PP_HEIGHT_BITS value
#endif
}
static inline int ssd16xx_set_ram_param(struct ssd16xx_data *driver,
u16_t sx, u16_t ex, u16_t sy, u16_t ey)
{
int err;
u8_t tmp[4];
size_t len;
len = push_x_param(tmp, sx);
len += push_x_param(tmp + len, ex);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_RAM_XPOS_CTRL, tmp, len);
if (err < 0) {
return err;
}
len = push_y_param(tmp, sy);
len += push_y_param(tmp + len, ey);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_RAM_YPOS_CTRL, tmp, len);
if (err < 0) {
return err;
}
return 0;
}
static inline int ssd16xx_set_ram_ptr(struct ssd16xx_data *driver,
u16_t x, u16_t y)
{
int err;
u8_t tmp[2];
size_t len;
len = push_x_param(tmp, x);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_RAM_XPOS_CNTR, tmp, len);
if (err < 0) {
return err;
}
len = push_y_param(tmp, y);
return ssd16xx_write_cmd(driver, SSD16XX_CMD_RAM_YPOS_CNTR, tmp, len);
}
static void ssd16xx_set_orientation_internall(struct ssd16xx_data *driver)
{
#if DT_INST_0_SOLOMON_SSD16XXFB_ORIENTATION_FLIPPED == 1
driver->scan_mode = SSD16XX_DATA_ENTRY_XIYDY;
#else
driver->scan_mode = SSD16XX_DATA_ENTRY_XDYIY;
#endif
}
int ssd16xx_resume(const struct device *dev)
{
struct ssd16xx_data *driver = dev->driver_data;
u8_t tmp;
/*
* Uncomment for voltage measurement
* tmp = SSD16XX_CTRL2_ENABLE_CLK;
* ssd16xx_write_cmd(SSD16XX_CMD_UPDATE_CTRL2, &tmp, sizeof(tmp));
* ssd16xx_write_cmd(SSD16XX_CMD_MASTER_ACTIVATION, NULL, 0);
*/
tmp = SSD16XX_SLEEP_MODE_PON;
return ssd16xx_write_cmd(driver, SSD16XX_CMD_SLEEP_MODE,
&tmp, sizeof(tmp));
}
static int ssd16xx_suspend(const struct device *dev)
{
struct ssd16xx_data *driver = dev->driver_data;
u8_t tmp = SSD16XX_SLEEP_MODE_DSM;
return ssd16xx_write_cmd(driver, SSD16XX_CMD_SLEEP_MODE,
&tmp, sizeof(tmp));
}
static int ssd16xx_update_display(const struct device *dev)
{
struct ssd16xx_data *driver = dev->driver_data;
u8_t tmp;
int err;
tmp = SSD16XX_CTRL1_INITIAL_UPDATE_LH;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_UPDATE_CTRL1,
&tmp, sizeof(tmp));
if (err < 0) {
return err;
}
tmp = (SSD16XX_CTRL2_ENABLE_CLK |
SSD16XX_CTRL2_ENABLE_ANALOG |
SSD16XX_CTRL2_TO_PATTERN |
SSD16XX_CTRL2_DISABLE_ANALOG |
SSD16XX_CTRL2_DISABLE_CLK);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_UPDATE_CTRL2, &tmp,
sizeof(tmp));
if (err < 0) {
return err;
}
return ssd16xx_write_cmd(driver, SSD16XX_CMD_MASTER_ACTIVATION,
NULL, 0);
}
static int ssd16xx_write(const struct device *dev, const u16_t x,
const u16_t y,
const struct display_buffer_descriptor *desc,
const void *buf)
{
struct ssd16xx_data *driver = dev->driver_data;
int err;
u16_t x_start;
u16_t x_end;
u16_t y_start;
u16_t y_end;
if (desc->pitch < desc->width) {
LOG_ERR("Pitch is smaller than width");
return -EINVAL;
}
if (buf == NULL || desc->buf_size == 0U) {
LOG_ERR("Display buffer is not available");
return -EINVAL;
}
if (desc->pitch > desc->width) {
LOG_ERR("Unsupported mode");
return -ENOTSUP;
}
if ((y + desc->height) > EPD_PANEL_HEIGHT) {
LOG_ERR("Buffer out of bounds (height)");
return -EINVAL;
}
if ((x + desc->width) > EPD_PANEL_WIDTH) {
LOG_ERR("Buffer out of bounds (width)");
return -EINVAL;
}
if ((desc->height % EPD_PANEL_NUMOF_ROWS_PER_PAGE) != 0U) {
LOG_ERR("Buffer height not multiple of %d",
EPD_PANEL_NUMOF_ROWS_PER_PAGE);
return -EINVAL;
}
if ((y % EPD_PANEL_NUMOF_ROWS_PER_PAGE) != 0U) {
LOG_ERR("Y coordinate not multiple of %d",
EPD_PANEL_NUMOF_ROWS_PER_PAGE);
return -EINVAL;
}
switch (driver->scan_mode) {
case SSD16XX_DATA_ENTRY_XIYDY:
x_start = y / SSD16XX_PIXELS_PER_BYTE;
x_end = (y + desc->height - 1) / SSD16XX_PIXELS_PER_BYTE;
y_start = (x + desc->width - 1);
y_end = x;
break;
case SSD16XX_DATA_ENTRY_XDYIY:
x_start = (EPD_PANEL_HEIGHT - 1 - y) / SSD16XX_PIXELS_PER_BYTE;
x_end = (EPD_PANEL_HEIGHT - 1 - (y + desc->height - 1)) /
SSD16XX_PIXELS_PER_BYTE;
y_start = x;
y_end = (x + desc->width - 1);
break;
default:
return -EINVAL;
}
ssd16xx_busy_wait(driver);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_ENTRY_MODE,
&driver->scan_mode, sizeof(driver->scan_mode));
if (err < 0) {
return err;
}
err = ssd16xx_set_ram_param(driver, x_start, x_end, y_start, y_end);
if (err < 0) {
return err;
}
err = ssd16xx_set_ram_ptr(driver, x_start, y_start);
if (err < 0) {
return err;
}
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_WRITE_RAM, (u8_t *)buf,
desc->buf_size);
if (err < 0) {
return err;
}
return ssd16xx_update_display(dev);
}
static int ssd16xx_read(const struct device *dev, const u16_t x,
const u16_t y,
const struct display_buffer_descriptor *desc,
void *buf)
{
LOG_ERR("not supported");
return -ENOTSUP;
}
static void *ssd16xx_get_framebuffer(const struct device *dev)
{
LOG_ERR("not supported");
return NULL;
}
static int ssd16xx_set_brightness(const struct device *dev,
const u8_t brightness)
{
LOG_WRN("not supported");
return -ENOTSUP;
}
static int ssd16xx_set_contrast(const struct device *dev, u8_t contrast)
{
LOG_WRN("not supported");
return -ENOTSUP;
}
static void ssd16xx_get_capabilities(const struct device *dev,
struct display_capabilities *caps)
{
memset(caps, 0, sizeof(struct display_capabilities));
caps->x_resolution = EPD_PANEL_WIDTH;
caps->y_resolution = EPD_PANEL_HEIGHT;
caps->supported_pixel_formats = PIXEL_FORMAT_MONO10;
caps->current_pixel_format = PIXEL_FORMAT_MONO10;
caps->screen_info = SCREEN_INFO_MONO_VTILED |
SCREEN_INFO_MONO_MSB_FIRST |
SCREEN_INFO_EPD |
SCREEN_INFO_DOUBLE_BUFFER;
}
static int ssd16xx_set_orientation(const struct device *dev,
const enum display_orientation
orientation)
{
LOG_ERR("Unsupported");
return -ENOTSUP;
}
static int ssd16xx_set_pixel_format(const struct device *dev,
const enum display_pixel_format pf)
{
if (pf == PIXEL_FORMAT_MONO10) {
return 0;
}
LOG_ERR("not supported");
return -ENOTSUP;
}
static int ssd16xx_clear_and_write_buffer(struct device *dev)
{
int err;
u8_t clear_page[EPD_PANEL_WIDTH];
u8_t page;
struct spi_buf sbuf;
struct spi_buf_set buf_set = {.buffers = &sbuf, .count = 1};
struct ssd16xx_data *driver = dev->driver_data;
u8_t tmp;
tmp = SSD16XX_DATA_ENTRY_XIYDY;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_ENTRY_MODE, &tmp, 1);
if (err < 0) {
return err;
}
err = ssd16xx_set_ram_param(driver, SSD16XX_PANEL_FIRST_PAGE,
SSD16XX_PANEL_LAST_PAGE + 1,
SSD16XX_PANEL_LAST_GATE,
SSD16XX_PANEL_FIRST_GATE);
if (err < 0) {
return err;
}
err = ssd16xx_set_ram_ptr(driver, SSD16XX_PANEL_FIRST_PAGE,
SSD16XX_PANEL_LAST_GATE);
if (err < 0) {
return err;
}
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_PIN, 0);
tmp = SSD16XX_CMD_WRITE_RAM;
sbuf.buf = &tmp;
sbuf.len = 1;
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
gpio_pin_write(driver->dc, DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_PIN, 1);
memset(clear_page, 0xff, sizeof(clear_page));
sbuf.buf = clear_page;
sbuf.len = sizeof(clear_page);
for (page = 0U; page <= (SSD16XX_PANEL_LAST_PAGE + 1); ++page) {
err = spi_write(driver->spi_dev, &driver->spi_config, &buf_set);
if (err < 0) {
return err;
}
}
return ssd16xx_update_display(dev);
}
static int ssd16xx_controller_init(struct device *dev)
{
int err;
u8_t tmp[3];
size_t len;
struct ssd16xx_data *driver = dev->driver_data;
LOG_DBG("");
gpio_pin_write(driver->reset, DT_INST_0_SOLOMON_SSD16XXFB_RESET_GPIOS_PIN, 0);
k_sleep(SSD16XX_RESET_DELAY);
gpio_pin_write(driver->reset, DT_INST_0_SOLOMON_SSD16XXFB_RESET_GPIOS_PIN, 1);
k_sleep(SSD16XX_RESET_DELAY);
ssd16xx_busy_wait(driver);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_SW_RESET, NULL, 0);
if (err < 0) {
return err;
}
ssd16xx_busy_wait(driver);
len = push_y_param(tmp, SSD16XX_PANEL_LAST_GATE);
tmp[len++] = 0U;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_GDO_CTRL, tmp, len);
if (err < 0) {
return err;
}
#if defined(DT_INST_0_SOLOMON_SSD16XXFB_SOFTSTART_1)
tmp[0] = DT_INST_0_SOLOMON_SSD16XXFB_SOFTSTART_1;
tmp[1] = DT_INST_0_SOLOMON_SSD16XXFB_SOFTSTART_2;
tmp[2] = DT_INST_0_SOLOMON_SSD16XXFB_SOFTSTART_3;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_SOFTSTART, tmp, 3);
if (err < 0) {
return err;
}
#endif
tmp[0] = DT_INST_0_SOLOMON_SSD16XXFB_GDV_A;
#if defined(DT_INST_0_SOLOMON_SSD16XXFB_GDV_B)
tmp[1] = DT_INST_0_SOLOMON_SSD16XXFB_GDV_B;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_GDV_CTRL, tmp, 2);
#else
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_GDV_CTRL, tmp, 1);
#endif
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD16XXFB_SDV;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_SDV_CTRL, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD16XXFB_VCOM;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_VCOM_VOLTAGE, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = SSD16XX_VAL_DUMMY_LINE;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_DUMMY_LINE, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = SSD16XX_VAL_GATE_LWIDTH;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_GATE_LINE_WIDTH, tmp, 1);
if (err < 0) {
return err;
}
tmp[0] = DT_INST_0_SOLOMON_SSD16XXFB_BORDER_WAVEFORM;
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_BWF_CTRL, tmp, 1);
if (err < 0) {
return err;
}
ssd16xx_set_orientation_internall(driver);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_UPDATE_LUT,
ssd16xx_lut_initial,
sizeof(ssd16xx_lut_initial));
if (err < 0) {
return err;
}
err = ssd16xx_clear_and_write_buffer(dev);
if (err < 0) {
return err;
}
ssd16xx_busy_wait(driver);
err = ssd16xx_write_cmd(driver, SSD16XX_CMD_UPDATE_LUT,
ssd16xx_lut_default,
sizeof(ssd16xx_lut_default));
if (err < 0) {
return err;
}
return ssd16xx_clear_and_write_buffer(dev);
}
static int ssd16xx_init(struct device *dev)
{
struct ssd16xx_data *driver = dev->driver_data;
LOG_DBG("");
driver->spi_dev = device_get_binding(DT_INST_0_SOLOMON_SSD16XXFB_BUS_NAME);
if (driver->spi_dev == NULL) {
LOG_ERR("Could not get SPI device for SSD16XX");
return -EIO;
}
driver->spi_config.frequency = DT_INST_0_SOLOMON_SSD16XXFB_SPI_MAX_FREQUENCY;
driver->spi_config.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8);
driver->spi_config.slave = DT_INST_0_SOLOMON_SSD16XXFB_BASE_ADDRESS;
driver->spi_config.cs = NULL;
driver->reset = device_get_binding(DT_INST_0_SOLOMON_SSD16XXFB_RESET_GPIOS_CONTROLLER);
if (driver->reset == NULL) {
LOG_ERR("Could not get GPIO port for SSD16XX reset");
return -EIO;
}
gpio_pin_configure(driver->reset, DT_INST_0_SOLOMON_SSD16XXFB_RESET_GPIOS_PIN,
GPIO_DIR_OUT);
driver->dc = device_get_binding(DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_CONTROLLER);
if (driver->dc == NULL) {
LOG_ERR("Could not get GPIO port for SSD16XX DC signal");
return -EIO;
}
gpio_pin_configure(driver->dc, DT_INST_0_SOLOMON_SSD16XXFB_DC_GPIOS_PIN,
GPIO_DIR_OUT);
driver->busy = device_get_binding(DT_INST_0_SOLOMON_SSD16XXFB_BUSY_GPIOS_CONTROLLER);
if (driver->busy == NULL) {
LOG_ERR("Could not get GPIO port for SSD16XX busy signal");
return -EIO;
}
gpio_pin_configure(driver->busy, DT_INST_0_SOLOMON_SSD16XXFB_BUSY_GPIOS_PIN,
GPIO_DIR_IN);
#if defined(DT_INST_0_SOLOMON_SSD16XXFB_CS_GPIOS_CONTROLLER)
driver->cs_ctrl.gpio_dev = device_get_binding(
DT_INST_0_SOLOMON_SSD16XXFB_CS_GPIOS_CONTROLLER);
if (!driver->cs_ctrl.gpio_dev) {
LOG_ERR("Unable to get SPI GPIO CS device");
return -EIO;
}
driver->cs_ctrl.gpio_pin = DT_INST_0_SOLOMON_SSD16XXFB_CS_GPIOS_PIN;
driver->cs_ctrl.delay = 0U;
driver->spi_config.cs = &driver->cs_ctrl;
#endif
return ssd16xx_controller_init(dev);
}
static struct ssd16xx_data ssd16xx_driver;
static struct display_driver_api ssd16xx_driver_api = {
.blanking_on = ssd16xx_resume,
.blanking_off = ssd16xx_suspend,
.write = ssd16xx_write,
.read = ssd16xx_read,
.get_framebuffer = ssd16xx_get_framebuffer,
.set_brightness = ssd16xx_set_brightness,
.set_contrast = ssd16xx_set_contrast,
.get_capabilities = ssd16xx_get_capabilities,
.set_pixel_format = ssd16xx_set_pixel_format,
.set_orientation = ssd16xx_set_orientation,
};
DEVICE_AND_API_INIT(ssd16xx, DT_INST_0_SOLOMON_SSD16XXFB_LABEL, ssd16xx_init,
&ssd16xx_driver, NULL,
POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY,
&ssd16xx_driver_api);

View file

@ -0,0 +1,77 @@
/* ssd16xx_regs.h - Registers definition for SSD16XX compatible controller */
/*
* Copyright (c) 2018 PHYTEC Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SSD16XX_REGS_H__
#define __SSD16XX_REGS_H__
#define SSD16XX_CMD_GDO_CTRL 0x01
#define SSD16XX_CMD_GDV_CTRL 0x03
#define SSD16XX_CMD_SDV_CTRL 0x04
#define SSD16XX_CMD_SOFTSTART 0x0c
#define SSD16XX_CMD_GSCAN_START 0x0f
#define SSD16XX_CMD_SLEEP_MODE 0x10
#define SSD16XX_CMD_ENTRY_MODE 0x11
#define SSD16XX_CMD_SW_RESET 0x12
#define SSD16XX_CMD_TSENS_CTRL 0x1a
#define SSD16XX_CMD_MASTER_ACTIVATION 0x20
#define SSD16XX_CMD_UPDATE_CTRL1 0x21
#define SSD16XX_CMD_UPDATE_CTRL2 0x22
#define SSD16XX_CMD_WRITE_RAM 0x24
#define SSD16XX_CMD_VCOM_SENSE 0x28
#define SSD16XX_CMD_VCOM_SENSE_DURATON 0x29
#define SSD16XX_CMD_PRGM_VCOM_OTP 0x2a
#define SSD16XX_CMD_VCOM_VOLTAGE 0x2c
#define SSD16XX_CMD_PRGM_WS_OTP 0x30
#define SSD16XX_CMD_UPDATE_LUT 0x32
#define SSD16XX_CMD_PRGM_OTP_SELECTION 0x36
#define SSD16XX_CMD_OTP_SELECTION_CTRL 0x37
#define SSD16XX_CMD_DUMMY_LINE 0x3a
#define SSD16XX_CMD_GATE_LINE_WIDTH 0x3b
#define SSD16XX_CMD_BWF_CTRL 0x3c
#define SSD16XX_CMD_RAM_XPOS_CTRL 0x44
#define SSD16XX_CMD_RAM_YPOS_CTRL 0x45
#define SSD16XX_CMD_RAM_XPOS_CNTR 0x4e
#define SSD16XX_CMD_RAM_YPOS_CNTR 0x4f
/* Data entry sequence modes */
#define SSD16XX_DATA_ENTRY_MASK 0x07
#define SSD16XX_DATA_ENTRY_XDYDX 0x00
#define SSD16XX_DATA_ENTRY_XIYDX 0x01
#define SSD16XX_DATA_ENTRY_XDYIX 0x02
#define SSD16XX_DATA_ENTRY_XIYIX 0x03
#define SSD16XX_DATA_ENTRY_XDYDY 0x04
#define SSD16XX_DATA_ENTRY_XIYDY 0x05
#define SSD16XX_DATA_ENTRY_XDYIY 0x06
#define SSD16XX_DATA_ENTRY_XIYIY 0x07
/* Options for display update */
#define SSD16XX_CTRL1_INITIAL_UPDATE_LL 0x00
#define SSD16XX_CTRL1_INITIAL_UPDATE_LH 0x01
#define SSD16XX_CTRL1_INITIAL_UPDATE_HL 0x02
#define SSD16XX_CTRL1_INITIAL_UPDATE_HH 0x03
/* Options for display update sequence */
#define SSD16XX_CTRL2_ENABLE_CLK 0x80
#define SSD16XX_CTRL2_ENABLE_ANALOG 0x40
#define SSD16XX_CTRL2_TO_INITIAL 0x08
#define SSD16XX_CTRL2_TO_PATTERN 0x04
#define SSD16XX_CTRL2_DISABLE_ANALOG 0x02
#define SSD16XX_CTRL2_DISABLE_CLK 0x01
#define SSD16XX_SLEEP_MODE_DSM 0x01
#define SSD16XX_SLEEP_MODE_PON 0x00
/* 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
#endif /* __SSD16XX_REGS_H__ */

View file

@ -4,18 +4,18 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
title: SSD1673 250x150 EPD Display Controller title: SSD16XX 250x150 EPD Display Controller
version: 0.1 version: 0.1
description: > description: >
This is a representation of the SSD1673 250x150 EPD Display Controller This is a representation of the SSD16XX 250x150 EPD Display Controller
inherits: inherits:
!include spi-device.yaml !include spi-device.yaml
properties: properties:
compatible: compatible:
constraint: "solomon,ssd1673fb" constraint: "solomon,ssd16xxfb"
height: height:
type: int type: int

View file

@ -61,7 +61,7 @@ CONFIG_SPI_ASYNC=y
CONFIG_HEAP_MEM_POOL_SIZE=16384 CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_DISPLAY=y CONFIG_DISPLAY=y
CONFIG_SSD1673=y CONFIG_SSD16XX=y
CONFIG_CHARACTER_FRAMEBUFFER=y CONFIG_CHARACTER_FRAMEBUFFER=y

View file

@ -35,7 +35,7 @@ static struct device_info dev_info[] = {
{ NULL, DT_INST_0_TI_HDC1010_LABEL }, { NULL, DT_INST_0_TI_HDC1010_LABEL },
{ NULL, DT_INST_0_NXP_MMA8652FC_LABEL }, { NULL, DT_INST_0_NXP_MMA8652FC_LABEL },
{ NULL, DT_INST_0_AVAGO_APDS9960_LABEL }, { NULL, DT_INST_0_AVAGO_APDS9960_LABEL },
{ NULL, DT_INST_0_SOLOMON_SSD1673FB_LABEL }, { NULL, DT_INST_0_SOLOMON_SSD16XXFB_LABEL },
}; };
static void configure_gpios(void) static void configure_gpios(void)

View file

@ -588,9 +588,9 @@ void board_refresh_display(void)
int board_init(void) int board_init(void)
{ {
epd_dev = device_get_binding(DT_INST_0_SOLOMON_SSD1673FB_LABEL); epd_dev = device_get_binding(DT_INST_0_SOLOMON_SSD16XXFB_LABEL);
if (epd_dev == NULL) { if (epd_dev == NULL) {
printk("SSD1673 device not found\n"); printk("SSD16XX device not found\n");
return -ENODEV; return -ENODEV;
} }

View file

@ -1,2 +1,2 @@
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_SSD1673=y CONFIG_SSD16XX=y

View file

@ -7,5 +7,5 @@ sample:
tests: tests:
sample.display.cfb.ssd1306: sample.display.cfb.ssd1306:
platform_whitelist: frdm_k64f platform_whitelist: frdm_k64f
sample.display.cfb.ssd1673: sample.display.cfb.ssd16xx:
platform_whitelist: reel_board platform_whitelist: reel_board

View file

@ -9,8 +9,8 @@
#include <display/cfb.h> #include <display/cfb.h>
#include <stdio.h> #include <stdio.h>
#if defined(CONFIG_SSD1673) #if defined(CONFIG_SSD16XX)
#define DISPLAY_DRIVER "SSD1673" #define DISPLAY_DRIVER "SSD16XX"
#endif #endif
#if defined(CONFIG_SSD1306) #if defined(CONFIG_SSD1306)

View file

@ -25,11 +25,11 @@ directory:
Generic config file, normally you should use this. Generic config file, normally you should use this.
- :file:`boards/reel_board.conf` - :file:`boards/reel_board.conf`
This overlay config enables support for SSD1673 display controller This overlay config enables support for SSD16XX display controller
on the reel_board. on the reel_board.
Example building for the reel_board with SSD1673 display support: Example building for the reel_board with SSD16XX display support:
.. zephyr-app-commands:: .. zephyr-app-commands::
:zephyr-app: samples/display/cfb_custom_font :zephyr-app: samples/display/cfb_custom_font

View file

@ -1,2 +1,2 @@
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_SSD1673=y CONFIG_SSD16XX=y

View file

@ -5,5 +5,5 @@ sample:
description: Custom character framebuffer font example description: Custom character framebuffer font example
name: cfb custom font sample name: cfb custom font sample
tests: tests:
sample.display.cfb_custom_font.ssd1673: sample.display.cfb_custom_font.ssd16xx:
platform_whitelist: reel_board platform_whitelist: reel_board

View file

@ -11,8 +11,8 @@
#include "cfb_font_dice.h" #include "cfb_font_dice.h"
#if defined(CONFIG_SSD1673) #if defined(CONFIG_SSD16XX)
#define DISPLAY_DRIVER "SSD1673" #define DISPLAY_DRIVER "SSD16XX"
#else #else
#error Unsupported board #error Unsupported board
#endif #endif

View file

@ -46,7 +46,7 @@ Command example (reel_board):
.. code-block:: console .. code-block:: console
uart:~$ cfb init uart:~$ cfb init
Framebuffer initialized: SSD1673 Framebuffer initialized: SSD16XX
Display Cleared Display Cleared
**get_device**: prints the display device name. **get_device**: prints the display device name.
@ -56,7 +56,7 @@ Command example (reel_board):
.. code-block:: console .. code-block:: console
uart:~$ cfb get_device uart:~$ cfb get_device
Framebuffer Device: SSD1673 Framebuffer Device: SSD16XX
**get_param**: get the display parameters where height, width and ppt **get_param**: get the display parameters where height, width and ppt
(pixel per tile) are in pixels and the number of rows and columns. The row (pixel per tile) are in pixels and the number of rows and columns. The row

View file

@ -1,2 +1,2 @@
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_SSD1673=y CONFIG_SSD16XX=y

View file

@ -7,5 +7,5 @@ sample:
tests: tests:
sample.display.cfb_shell.ssd1306: sample.display.cfb_shell.ssd1306:
platform_whitelist: frdm_k64f platform_whitelist: frdm_k64f
sample.display.cfb_shell.ssd1673: sample.display.cfb_shell.ssd16xx:
platform_whitelist: reel_board platform_whitelist: reel_board

View file

@ -1,5 +1,5 @@
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_SSD1673=y CONFIG_SSD16XX=y
CONFIG_LVGL_COLOR_DEPTH_1=y CONFIG_LVGL_COLOR_DEPTH_1=y
CONFIG_LVGL_BITS_PER_PIXEL=1 CONFIG_LVGL_BITS_PER_PIXEL=1

View file

@ -5,7 +5,7 @@
*/ */
&spi3 { &spi3 {
ssd1673fb@0 { ssd16xxfb@0 {
label = "DISPLAY"; label = "DISPLAY";
}; };
}; };

View file

@ -29,7 +29,7 @@ config CHARACTER_FRAMEBUFFER_SHELL
if CHARACTER_FRAMEBUFFER_SHELL if CHARACTER_FRAMEBUFFER_SHELL
config CHARACTER_FRAMEBUFFER_SHELL_DRIVER_NAME config CHARACTER_FRAMEBUFFER_SHELL_DRIVER_NAME
string string
default "SSD1673" if SSD1673 default "SSD16XX" if SSD16XX
default "SSD1306" if SSD1306 default "SSD1306" if SSD1306
help help
Character Framebuffer Display Driver Name Character Framebuffer Display Driver Name