Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 134 additions & 15 deletions drivers/display/ssd16xx.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2022 Andreas Sandberg
* Copyright (c) 2018-2020 PHYTEC Messtechnik GmbH
*
* SPDX-License-Identifier: Apache-2.0
Expand All @@ -18,6 +19,7 @@ LOG_MODULE_REGISTER(ssd16xx);
#include <zephyr/drivers/spi.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/display/ssd16xx.h>
#include "ssd16xx_regs.h"

/**
Expand All @@ -32,6 +34,7 @@ LOG_MODULE_REGISTER(ssd16xx);
#define SSD16XX_TR_SCALE_FACTOR 256U

struct ssd16xx_data {
bool read_supported;
uint8_t scan_mode;
uint8_t update_cmd;
bool blanking_on;
Expand Down Expand Up @@ -114,6 +117,51 @@ static inline int ssd16xx_write_cmd(const struct device *dev, uint8_t cmd,
return err;
}

static inline int ssd16xx_read_cmd(const struct device *dev, uint8_t cmd,
uint8_t *data, size_t len)
{
const struct ssd16xx_config *config = dev->config;
const struct ssd16xx_data *dev_data = dev->data;
struct spi_buf buf = {.buf = &cmd, .len = sizeof(cmd)};
struct spi_buf_set buf_set = {.buffers = &buf, .count = 1};
int err = 0;

if (!dev_data->read_supported) {
return -ENOTSUP;
}

ssd16xx_busy_wait(dev);

err = gpio_pin_set_dt(&config->dc_gpio, 1);
if (err < 0) {
return err;
}

err = spi_write_dt(&config->bus, &buf_set);
if (err < 0) {
goto spi_out;
}

if (data != NULL) {
buf.buf = data;
buf.len = len;

err = gpio_pin_set_dt(&config->dc_gpio, 0);
if (err < 0) {
goto spi_out;
}

err = spi_read_dt(&config->bus, &buf_set);
if (err < 0) {
goto spi_out;
}
}

spi_out:
spi_release_dt(&config->bus);
return err;
}

static inline size_t push_x_param(const struct device *dev,
uint8_t *data, uint16_t x)
{
Expand Down Expand Up @@ -231,15 +279,13 @@ static int ssd16xx_blanking_on(const struct device *dev)
return 0;
}

static int ssd16xx_write(const struct device *dev, const uint16_t x,
const uint16_t y,
const struct display_buffer_descriptor *desc,
const void *buf)
static int ssd16xx_set_window(const struct device *dev,
const uint16_t x, const uint16_t y,
const struct display_buffer_descriptor *desc)
{
const struct ssd16xx_config *config = dev->config;
struct ssd16xx_data *data = dev->data;
int err;
size_t buf_len;
uint16_t x_start;
uint16_t x_end;
uint16_t y_start;
Expand All @@ -252,12 +298,6 @@ static int ssd16xx_write(const struct device *dev, const uint16_t x,
return -EINVAL;
}

buf_len = MIN(desc->buf_size, desc->height * desc->width / 8);
if (buf == NULL || buf_len == 0U) {
LOG_ERR("Display buffer is not available");
return -EINVAL;
}

if (desc->pitch > desc->width) {
LOG_ERR("Unsupported mode");
return -ENOTSUP;
Expand Down Expand Up @@ -320,6 +360,29 @@ static int ssd16xx_write(const struct device *dev, const uint16_t x,
return err;
}

return 0;
}

static int ssd16xx_write(const struct device *dev, const uint16_t x,
const uint16_t y,
const struct display_buffer_descriptor *desc,
const void *buf)
{
const struct ssd16xx_data *data = dev->data;
const size_t buf_len = MIN(desc->buf_size,
desc->height * desc->width / 8);
int err;

if (buf == NULL || buf_len == 0U) {
LOG_ERR("Display buffer is not available");
return -EINVAL;
}

err = ssd16xx_set_window(dev, x, y, desc);
if (err < 0) {
return err;
}

err = ssd16xx_write_cmd(dev, SSD16XX_CMD_WRITE_RAM, (uint8_t *)buf,
buf_len);
if (err < 0) {
Expand All @@ -336,13 +399,65 @@ static int ssd16xx_write(const struct device *dev, const uint16_t x,
return 0;
}

static int ssd16xx_read(const struct device *dev, const uint16_t x,
const uint16_t y,
int ssd16xx_read_ram(const struct device *dev, enum ssd16xx_ram ram_type,
const uint16_t x, const uint16_t y,
const struct display_buffer_descriptor *desc,
void *buf)
{
const struct ssd16xx_data *data = dev->data;
const size_t buf_len = MIN(desc->buf_size,
desc->height * desc->width / 8);
int err;
uint8_t ram_ctrl;

if (!data->read_supported) {
return -ENOTSUP;
}

switch (ram_type) {
case SSD16XX_RAM_BLACK:
ram_ctrl = SSD16XX_RAM_READ_CTRL_BLACK;
break;

case SSD16XX_RAM_RED:
ram_ctrl = SSD16XX_RAM_READ_CTRL_RED;
break;

default:
return -EINVAL;
}

if (buf == NULL || buf_len == 0U) {
LOG_ERR("Display buffer is not available");
return -EINVAL;
}

err = ssd16xx_set_window(dev, x, y, desc);
if (err < 0) {
return err;
}

err = ssd16xx_write_cmd(dev, SSD16XX_CMD_RAM_READ_CTRL,
&ram_ctrl, sizeof(ram_ctrl));
if (err < 0) {
return err;
}

err = ssd16xx_read_cmd(dev, SSD16XX_CMD_READ_RAM, (uint8_t *)buf,
buf_len);
if (err < 0) {
return err;
}

return 0;
}

static int ssd16xx_read(const struct device *dev,
const uint16_t x, const uint16_t y,
const struct display_buffer_descriptor *desc,
void *buf)
{
LOG_ERR("not supported");
return -ENOTSUP;
return ssd16xx_read_ram(dev, SSD16XX_RAM_BLACK, x, y, desc, buf);
}

static void *ssd16xx_get_framebuffer(const struct device *dev)
Expand Down Expand Up @@ -674,6 +789,7 @@ static int ssd16xx_controller_init(const struct device *dev)
static int ssd16xx_init(const struct device *dev)
{
const struct ssd16xx_config *config = dev->config;
struct ssd16xx_data *data = dev->data;
int err;

LOG_DBG("");
Expand All @@ -683,6 +799,9 @@ static int ssd16xx_init(const struct device *dev)
return -ENODEV;
}

data->read_supported =
(config->bus.config.operation & SPI_HALF_DUPLEX) != 0;

if (!device_is_ready(config->reset_gpio.port)) {
LOG_ERR("Reset GPIO device not ready");
return -ENODEV;
Expand Down
9 changes: 9 additions & 0 deletions drivers/display/ssd16xx_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@
#define SSD16XX_CMD_SW_RESET 0x12
#define SSD16XX_CMD_TSENSOR_SELECTION 0x18
#define SSD16XX_CMD_TSENS_CTRL 0x1a
#define SSD16XX_CMD_READ_TSENS_CTRL 0x1b
#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_WRITE_RED_RAM 0x26
#define SSD16XX_CMD_READ_RAM 0x27
#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_READ_OTP_REG 0x2d
#define SSD16XX_CMD_READ_USER_ID 0x2e
#define SSD16XX_CMD_READ_STATUS 0x2f
#define SSD16XX_CMD_PRGM_WS_OTP 0x30
#define SSD16XX_CMD_LOAD_WS_OTP 0x31
#define SSD16XX_CMD_UPDATE_LUT 0x32
Expand All @@ -36,6 +41,7 @@
#define SSD16XX_CMD_DUMMY_LINE 0x3a
#define SSD16XX_CMD_GATE_LINE_WIDTH 0x3b
#define SSD16XX_CMD_BWF_CTRL 0x3c
#define SSD16XX_CMD_RAM_READ_CTRL 0x41
#define SSD16XX_CMD_RAM_XPOS_CTRL 0x44
#define SSD16XX_CMD_RAM_YPOS_CTRL 0x45
#define SSD16XX_CMD_RAM_XPOS_CNTR 0x4e
Expand Down Expand Up @@ -71,6 +77,9 @@
#define SSD16XX_SLEEP_MODE_DSM 0x01
#define SSD16XX_SLEEP_MODE_PON 0x00

#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
Expand Down
46 changes: 46 additions & 0 deletions include/zephyr/display/ssd16xx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022 Andreas Sandberg
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DISPLAY_SSD16XX_H_
#define ZEPHYR_INCLUDE_DISPLAY_SSD16XX_H_

#include <zephyr/drivers/display.h>

/**
* SSD16xx RAM type for direct RAM access
*/
enum ssd16xx_ram {
/** The black RAM buffer. This is typically the buffer used to
* compose the contents that will be displayed after the next
* refresh.
*/
SSD16XX_RAM_BLACK = 0,
/* The red RAM buffer. This is typically the old frame buffer
* when performing partial refreshes or an additional color
* channel.
*/
SSD16XX_RAM_RED,
};

/**
* @brief Read data directly from the display controller's internal
* RAM.
*
* @param dev Pointer to device structure
* @param ram_type Type of RAM to read from
* @param x Coordinate relative to the upper left corner
* @param y Coordinate relative to the upper left corner
* @param desc Structure describing the buffer layout
* @param buf Output buffer
*
* @retval 0 on success, negative errno on failure.
*/
int ssd16xx_read_ram(const struct device *dev, enum ssd16xx_ram ram_type,
const uint16_t x, const uint16_t y,
const struct display_buffer_descriptor *desc,
void *buf);

#endif /* ZEPHYR_INCLUDE_DISPLAY_SSD16XX_H_ */