drivers: ssd1306: Add SPI support
This change allows to use SSD1306 based displays to be used on the SPI bus as well. Adding SPI shield. Tested on SSD1306 and SSD1309 based displays using I2C. Tested on SSD1309 based display using SPI. Signed-off-by: Marco Peter <marco@peter-net.ch>
This commit is contained in:
parent
fd2087e080
commit
03f256505c
8 changed files with 143 additions and 26 deletions
|
@ -1,13 +1,24 @@
|
|||
# Copyright (c) 2019 Linaro Limited
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X32 || SHIELD_SH1106_128X64
|
||||
if SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X64_SPI || SHIELD_SSD1306_128X32 || SHIELD_SH1106_128X64
|
||||
|
||||
if DISPLAY
|
||||
|
||||
if SHIELD_SSD1306_128X64_SPI
|
||||
|
||||
config SPI
|
||||
default y
|
||||
|
||||
endif # SHIELD_SSD1306_128X64_SPI
|
||||
|
||||
if SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X32 || SHIELD_SH1106_128X64
|
||||
|
||||
config I2C
|
||||
default y
|
||||
|
||||
endif # SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X32 || SHIELD_SH1106_128X64
|
||||
|
||||
config SSD1306
|
||||
default y
|
||||
|
||||
|
@ -45,4 +56,4 @@ endif # LVGL
|
|||
|
||||
endif # DISPLAY
|
||||
|
||||
endif # SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X32
|
||||
endif # SHIELD_SSD1306_128X64 || SHIELD_SSD1306_128X64_SPI || SHIELD_SSD1306_128X32 || SHIELD_SH1106_128X64
|
||||
|
|
|
@ -7,5 +7,8 @@ config SHIELD_SSD1306_128X32
|
|||
config SHIELD_SSD1306_128X64
|
||||
def_bool $(shields_list_contains,ssd1306_128x64)
|
||||
|
||||
config SHIELD_SSD1306_128X64_SPI
|
||||
def_bool $(shields_list_contains,ssd1306_128x64_spi)
|
||||
|
||||
config SHIELD_SH1106_128X64
|
||||
def_bool $(shields_list_contains,sh1106_128x64)
|
||||
|
|
26
boards/shields/ssd1306/ssd1306_128x64_spi.overlay
Normal file
26
boards/shields/ssd1306/ssd1306_128x64_spi.overlay
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Marco Peter
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&arduino_spi {
|
||||
status = "okay";
|
||||
|
||||
ssd1306@0 {
|
||||
compatible = "solomon,ssd1306fb";
|
||||
reg = <0x0>;
|
||||
label = "SSD1306";
|
||||
spi-max-frequency = <10000000>;
|
||||
width = <128>;
|
||||
height = <64>;
|
||||
segment-offset = <0>;
|
||||
page-offset = <0>;
|
||||
display-offset = <0>;
|
||||
multiplex-ratio = <63>;
|
||||
segment-remap;
|
||||
com-invdir;
|
||||
prechargep = <0x22>;
|
||||
data_cmd-gpios = <&arduino_header 16 0>;
|
||||
};
|
||||
};
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
menuconfig SSD1306
|
||||
bool "SSD1306 display driver"
|
||||
depends on I2C
|
||||
depends on I2C || SPI
|
||||
help
|
||||
Enable driver for SSD1306 display driver.
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ LOG_MODULE_REGISTER(ssd1306, CONFIG_DISPLAY_LOG_LEVEL);
|
|||
#include <init.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/i2c.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
#include "ssd1306_regs.h"
|
||||
#include <display/cfb.h>
|
||||
|
@ -48,22 +49,54 @@ LOG_MODULE_REGISTER(ssd1306, CONFIG_DISPLAY_LOG_LEVEL);
|
|||
|
||||
struct ssd1306_data {
|
||||
const struct device *reset;
|
||||
const struct device *i2c;
|
||||
const struct device *bus;
|
||||
#if DT_INST_ON_BUS(0, spi)
|
||||
struct spi_cs_control cs_ctrl;
|
||||
struct spi_config spi_config;
|
||||
const struct device *data_cmd;
|
||||
#endif
|
||||
uint8_t contrast;
|
||||
uint8_t scan_mode;
|
||||
};
|
||||
|
||||
static inline int ssd1306_write_i2c(const struct device *dev,
|
||||
#if DT_INST_ON_BUS(0, i2c)
|
||||
static inline int ssd1306_write_bus(const struct device *dev,
|
||||
uint8_t *buf, size_t len, bool command)
|
||||
{
|
||||
struct ssd1306_data *driver = dev->data;
|
||||
|
||||
return i2c_burst_write(driver->i2c, DT_INST_REG_ADDR(0),
|
||||
return i2c_burst_write(driver->bus, DT_INST_REG_ADDR(0),
|
||||
command ? SSD1306_CONTROL_ALL_BYTES_CMD :
|
||||
SSD1306_CONTROL_ALL_BYTES_DATA,
|
||||
buf, len);
|
||||
}
|
||||
|
||||
#elif DT_INST_ON_BUS(0, spi)
|
||||
|
||||
static inline int ssd1306_write_bus(const struct device *dev,
|
||||
uint8_t *buf, size_t len, bool command)
|
||||
{
|
||||
struct ssd1306_data *driver = dev->data;
|
||||
int errno;
|
||||
|
||||
gpio_pin_set(driver->data_cmd, DT_INST_GPIO_PIN(0, data_cmd_gpios),
|
||||
command ? 0 : 1);
|
||||
struct spi_buf tx_buf = {
|
||||
.buf = buf,
|
||||
.len = len
|
||||
};
|
||||
|
||||
struct spi_buf_set tx_bufs = {
|
||||
.buffers = &tx_buf,
|
||||
.count = 1
|
||||
};
|
||||
|
||||
errno = spi_write(driver->bus, &driver->spi_config, &tx_bufs);
|
||||
|
||||
return errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int ssd1306_set_panel_orientation(const struct device *dev)
|
||||
{
|
||||
uint8_t cmd_buf[] = {
|
||||
|
@ -75,7 +108,7 @@ static inline int ssd1306_set_panel_orientation(const struct device *dev)
|
|||
SSD1306_SET_COM_OUTPUT_SCAN_NORMAL)
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static inline int ssd1306_set_timing_setting(const struct device *dev)
|
||||
|
@ -89,7 +122,7 @@ static inline int ssd1306_set_timing_setting(const struct device *dev)
|
|||
SSD1306_PANEL_VCOM_DESEL_LEVEL
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static inline int ssd1306_set_hardware_config(const struct device *dev)
|
||||
|
@ -104,7 +137,7 @@ static inline int ssd1306_set_hardware_config(const struct device *dev)
|
|||
DT_INST_PROP(0, multiplex_ratio)
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static inline int ssd1306_set_charge_pump(const struct device *dev)
|
||||
|
@ -121,7 +154,7 @@ static inline int ssd1306_set_charge_pump(const struct device *dev)
|
|||
SSD1306_PANEL_PUMP_VOLTAGE,
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static int ssd1306_resume(const struct device *dev)
|
||||
|
@ -130,7 +163,7 @@ static int ssd1306_resume(const struct device *dev)
|
|||
SSD1306_DISPLAY_ON,
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static int ssd1306_suspend(const struct device *dev)
|
||||
|
@ -139,7 +172,7 @@ static int ssd1306_suspend(const struct device *dev)
|
|||
SSD1306_DISPLAY_OFF,
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static int ssd1306_write(const struct device *dev, const uint16_t x, const uint16_t y,
|
||||
|
@ -184,12 +217,12 @@ static int ssd1306_write(const struct device *dev, const uint16_t x, const uint1
|
|||
((y + desc->height)/8 - 1)
|
||||
};
|
||||
|
||||
if (ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
if (ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
LOG_ERR("Failed to write command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ssd1306_write_i2c(dev, (uint8_t *)buf, buf_len, false);
|
||||
return ssd1306_write_bus(dev, (uint8_t *)buf, buf_len, false);
|
||||
|
||||
#elif defined(CONFIG_SSD1306_SH1106_COMPATIBLE)
|
||||
uint8_t x_offset = x + DT_INST_PROP(0, segment_offset);
|
||||
|
@ -207,11 +240,11 @@ static int ssd1306_write(const struct device *dev, const uint16_t x, const uint1
|
|||
SSD1306_SET_PAGE_START_ADDRESS | (n + (y / 8));
|
||||
LOG_HEXDUMP_DBG(cmd_buf, sizeof(cmd_buf), "cmd_buf");
|
||||
|
||||
if (ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
if (ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssd1306_write_i2c(dev, buf_ptr, desc->width, false)) {
|
||||
if (ssd1306_write_bus(dev, buf_ptr, desc->width, false)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -255,7 +288,7 @@ static int ssd1306_set_contrast(const struct device *dev, const uint8_t contrast
|
|||
contrast,
|
||||
};
|
||||
|
||||
return ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
return ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true);
|
||||
}
|
||||
|
||||
static void ssd1306_get_capabilities(const struct device *dev,
|
||||
|
@ -330,7 +363,7 @@ static int ssd1306_init_device(const struct device *dev)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (ssd1306_write_i2c(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
if (ssd1306_write_bus(dev, cmd_buf, sizeof(cmd_buf), true)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -349,8 +382,8 @@ static int ssd1306_init(const struct device *dev)
|
|||
|
||||
LOG_DBG("");
|
||||
|
||||
driver->i2c = device_get_binding(DT_INST_BUS_LABEL(0));
|
||||
if (driver->i2c == NULL) {
|
||||
driver->bus = device_get_binding(DT_INST_BUS_LABEL(0));
|
||||
if (driver->bus == NULL) {
|
||||
LOG_ERR("Failed to get pointer to %s device!",
|
||||
DT_INST_BUS_LABEL(0));
|
||||
return -EINVAL;
|
||||
|
@ -371,6 +404,34 @@ static int ssd1306_init(const struct device *dev)
|
|||
DT_INST_GPIO_FLAGS(0, reset_gpios));
|
||||
#endif
|
||||
|
||||
#if DT_INST_ON_BUS(0, spi)
|
||||
driver->spi_config.frequency = DT_INST_PROP(0, spi_max_frequency);
|
||||
driver->spi_config.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB |
|
||||
SPI_WORD_SET(8) | SPI_LINES_SINGLE |
|
||||
SPI_HOLD_ON_CS | SPI_LOCK_ON;
|
||||
driver->spi_config.slave = DT_INST_REG_ADDR(0);
|
||||
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
|
||||
driver->cs_ctrl.gpio_dev = device_get_binding(
|
||||
DT_INST_SPI_DEV_CS_GPIOS_LABEL(0));
|
||||
driver->cs_ctrl.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(0);
|
||||
driver->cs_ctrl.delay = 0U;
|
||||
driver->spi_config.cs = &driver->cs_ctrl;
|
||||
#endif /* DT_INST_SPI_DEV_HAS_CS_GPIOS(0) */
|
||||
|
||||
driver->data_cmd = device_get_binding(
|
||||
DT_INST_GPIO_LABEL(0, data_cmd_gpios));
|
||||
if (driver->data_cmd == NULL) {
|
||||
LOG_ERR("Failed to get pointer to %s device!",
|
||||
DT_INST_GPIO_LABEL(0, data_cmd_gpios));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_pin_configure(driver->data_cmd,
|
||||
DT_INST_GPIO_PIN(0, data_cmd_gpios),
|
||||
GPIO_OUTPUT_INACTIVE |
|
||||
DT_INST_GPIO_FLAGS(0, data_cmd_gpios));
|
||||
#endif /* DT_INST_ON_BUS(0, spi) */
|
||||
|
||||
if (ssd1306_init_device(dev)) {
|
||||
LOG_ERR("Failed to initialize device!");
|
||||
return -EIO;
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
# Copyright (c) 2018, Phytec Messtechnik GmbH
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: SSD1306 128x64 dot-matrix display controller
|
||||
|
||||
compatible: "solomon,ssd1306fb"
|
||||
|
||||
include: i2c-device.yaml
|
||||
|
||||
properties:
|
||||
height:
|
||||
type: int
|
8
dts/bindings/display/solomon,ssd1306fb-i2c.yaml
Normal file
8
dts/bindings/display/solomon,ssd1306fb-i2c.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2020, Marco Peter
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: SSD1306 128x64 dot-matrix display controller on I2C bus
|
||||
|
||||
compatible: "solomon,ssd1306fb"
|
||||
|
||||
include: ["solomon,ssd1306fb-common.yaml", "i2c-device.yaml"]
|
14
dts/bindings/display/solomon,ssd1306fb-spi.yaml
Normal file
14
dts/bindings/display/solomon,ssd1306fb-spi.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Copyright (c) 2020, Marco Peter
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: SSD1306 128x64 dot-matrix display controller on SPI bus
|
||||
|
||||
compatible: "solomon,ssd1306fb"
|
||||
|
||||
include: ["solomon,ssd1306fb-common.yaml", "spi-device.yaml"]
|
||||
|
||||
properties:
|
||||
data_cmd-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: D/C# pin.
|
Loading…
Add table
Add a link
Reference in a new issue