drivers: mipi_dbi_spi: add 16-bit transfer to C4
Extends the MIPI DBI SPI driver class for operating mode C4, SPI 4-wire, with 16 write clocks to send one or multiple byte for commands. Generic data (e.g. GRAM) aligned to 16-bit are passed through and stuffed with bytes if required. Signed-off-by: Stephan Linz <linz@li-pro.net>
This commit is contained in:
parent
c809c3730d
commit
a68c1aa4ad
3 changed files with 189 additions and 17 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2023 NXP
|
* Copyright 2023 NXP
|
||||||
|
* Copyright 2024 TiaC Systems
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include <zephyr/drivers/mipi_dbi.h>
|
#include <zephyr/drivers/mipi_dbi.h>
|
||||||
#include <zephyr/drivers/spi.h>
|
#include <zephyr/drivers/spi.h>
|
||||||
#include <zephyr/drivers/gpio.h>
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(mipi_dbi_spi, CONFIG_MIPI_DBI_LOG_LEVEL);
|
LOG_MODULE_REGISTER(mipi_dbi_spi, CONFIG_MIPI_DBI_LOG_LEVEL);
|
||||||
|
@ -20,6 +22,8 @@ struct mipi_dbi_spi_config {
|
||||||
const struct gpio_dt_spec cmd_data;
|
const struct gpio_dt_spec cmd_data;
|
||||||
/* Reset GPIO */
|
/* Reset GPIO */
|
||||||
const struct gpio_dt_spec reset;
|
const struct gpio_dt_spec reset;
|
||||||
|
/* Minimum transfer bits */
|
||||||
|
const uint8_t xfr_min_bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mipi_dbi_spi_data {
|
struct mipi_dbi_spi_data {
|
||||||
|
@ -38,6 +42,18 @@ struct mipi_dbi_spi_data {
|
||||||
#define MIPI_DBI_SPI_READ_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_WRITE_ONLY_ABSENT) 0
|
#define MIPI_DBI_SPI_READ_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_WRITE_ONLY_ABSENT) 0
|
||||||
uint32_t var = MIPI_DBI_SPI_READ_REQUIRED;
|
uint32_t var = MIPI_DBI_SPI_READ_REQUIRED;
|
||||||
|
|
||||||
|
/* Expands to 1 if the node does reflect the enum in `xfr-min-bits` property */
|
||||||
|
#define _XFR_8BITS(n) (DT_INST_PROP(n, xfr_min_bits) == MIPI_DBI_SPI_XFR_8BIT) |
|
||||||
|
#define _XFR_16BITS(n) (DT_INST_PROP(n, xfr_min_bits) == MIPI_DBI_SPI_XFR_16BIT) |
|
||||||
|
|
||||||
|
/* This macros will evaluate to 1 if any of the nodes with zephyr,mipi-dbi-spi
|
||||||
|
* have the `xfr-min-bits` property to corresponding enum value. The intention
|
||||||
|
* here is to allow the write helper functions to be optimized out when not all
|
||||||
|
* minimum transfer bits will be needed.
|
||||||
|
*/
|
||||||
|
#define MIPI_DBI_SPI_WRITE_8BIT_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_XFR_8BITS) 0
|
||||||
|
#define MIPI_DBI_SPI_WRITE_16BIT_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_XFR_16BITS) 0
|
||||||
|
|
||||||
/* In Type C mode 1 MIPI BIT communication, the 9th bit of the word
|
/* In Type C mode 1 MIPI BIT communication, the 9th bit of the word
|
||||||
* (first bit sent in each word) indicates if the word is a command or
|
* (first bit sent in each word) indicates if the word is a command or
|
||||||
* data. Typically 0 indicates a command and 1 indicates data, but some
|
* data. Typically 0 indicates a command and 1 indicates data, but some
|
||||||
|
@ -93,11 +109,13 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MIPI_DBI_SPI_WRITE_8BIT_REQUIRED
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
mipi_dbi_spi_write_helper_4wire(const struct device *dev,
|
mipi_dbi_spi_write_helper_4wire_8bit(const struct device *dev,
|
||||||
const struct mipi_dbi_config *dbi_config,
|
const struct mipi_dbi_config *dbi_config,
|
||||||
bool cmd_present, uint8_t cmd,
|
bool cmd_present, uint8_t cmd,
|
||||||
const uint8_t *data_buf, size_t len)
|
const uint8_t *data_buf, size_t len)
|
||||||
{
|
{
|
||||||
const struct mipi_dbi_spi_config *config = dev->config;
|
const struct mipi_dbi_spi_config *config = dev->config;
|
||||||
struct spi_buf buffer;
|
struct spi_buf buffer;
|
||||||
|
@ -140,11 +158,104 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* MIPI_DBI_SPI_WRITE_8BIT_REQUIRED */
|
||||||
|
|
||||||
|
#if MIPI_DBI_SPI_WRITE_16BIT_REQUIRED
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
mipi_dbi_spi_write_helper_4wire_16bit(const struct device *dev,
|
||||||
|
const struct mipi_dbi_config *dbi_config,
|
||||||
|
bool cmd_present, uint8_t cmd,
|
||||||
|
const uint8_t *data_buf, size_t len)
|
||||||
|
{
|
||||||
|
const struct mipi_dbi_spi_config *config = dev->config;
|
||||||
|
struct spi_buf buffer;
|
||||||
|
struct spi_buf_set buf_set = {
|
||||||
|
.buffers = &buffer,
|
||||||
|
.count = 1,
|
||||||
|
};
|
||||||
|
uint16_t data16;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4 wire mode with toggle the command/data GPIO
|
||||||
|
* to indicate if we are sending a command or data
|
||||||
|
* but send 16-bit blocks (with bit stuffing).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cmd_present) {
|
||||||
|
data16 = sys_cpu_to_be16(cmd);
|
||||||
|
buffer.buf = &data16;
|
||||||
|
buffer.len = sizeof(data16);
|
||||||
|
|
||||||
|
/* Set CD pin low for command */
|
||||||
|
gpio_pin_set_dt(&config->cmd_data, 0);
|
||||||
|
ret = spi_write(config->spi_dev, &dbi_config->config,
|
||||||
|
&buf_set);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set CD pin high for data, if there are any */
|
||||||
|
if (len > 0) {
|
||||||
|
gpio_pin_set_dt(&config->cmd_data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate command data */
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
data16 = sys_cpu_to_be16(data_buf[i]);
|
||||||
|
|
||||||
|
ret = spi_write(config->spi_dev, &dbi_config->config,
|
||||||
|
&buf_set);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int stuffing = len % sizeof(data16);
|
||||||
|
|
||||||
|
/* Set CD pin high for data, if there are any */
|
||||||
|
if (len > 0) {
|
||||||
|
gpio_pin_set_dt(&config->cmd_data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pass through generic device data */
|
||||||
|
if (len - stuffing > 0) {
|
||||||
|
buffer.buf = (void *)data_buf;
|
||||||
|
buffer.len = len - stuffing;
|
||||||
|
|
||||||
|
ret = spi_write(config->spi_dev, &dbi_config->config,
|
||||||
|
&buf_set);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iterate remaining data with stuffing */
|
||||||
|
for (int i = len - stuffing; i < len; i++) {
|
||||||
|
data16 = sys_cpu_to_be16(data_buf[i]);
|
||||||
|
buffer.buf = &data16;
|
||||||
|
buffer.len = sizeof(data16);
|
||||||
|
|
||||||
|
ret = spi_write(config->spi_dev, &dbi_config->config,
|
||||||
|
&buf_set);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MIPI_DBI_SPI_WRITE_16BIT_REQUIRED */
|
||||||
|
|
||||||
static int mipi_dbi_spi_write_helper(const struct device *dev,
|
static int mipi_dbi_spi_write_helper(const struct device *dev,
|
||||||
const struct mipi_dbi_config *dbi_config,
|
const struct mipi_dbi_config *dbi_config,
|
||||||
bool cmd_present, uint8_t cmd,
|
bool cmd_present, uint8_t cmd,
|
||||||
const uint8_t *data_buf, size_t len)
|
const uint8_t *data_buf, size_t len)
|
||||||
{
|
{
|
||||||
|
const struct mipi_dbi_spi_config *config = dev->config;
|
||||||
struct mipi_dbi_spi_data *data = dev->data;
|
struct mipi_dbi_spi_data *data = dev->data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -158,20 +269,36 @@ static int mipi_dbi_spi_write_helper(const struct device *dev,
|
||||||
ret = mipi_dbi_spi_write_helper_3wire(dev, dbi_config,
|
ret = mipi_dbi_spi_write_helper_3wire(dev, dbi_config,
|
||||||
cmd_present, cmd,
|
cmd_present, cmd,
|
||||||
data_buf, len);
|
data_buf, len);
|
||||||
if (ret < 0) {
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) {
|
|
||||||
ret = mipi_dbi_spi_write_helper_4wire(dev, dbi_config,
|
|
||||||
cmd_present, cmd,
|
|
||||||
data_buf, len);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Otherwise, unsupported mode */
|
|
||||||
ret = -ENOTSUP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) {
|
||||||
|
|
||||||
|
#if MIPI_DBI_SPI_WRITE_8BIT_REQUIRED
|
||||||
|
if (config->xfr_min_bits == MIPI_DBI_SPI_XFR_8BIT) {
|
||||||
|
ret = mipi_dbi_spi_write_helper_4wire_8bit(
|
||||||
|
dev, dbi_config,
|
||||||
|
cmd_present, cmd,
|
||||||
|
data_buf, len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MIPI_DBI_SPI_WRITE_16BIT_REQUIRED
|
||||||
|
if (config->xfr_min_bits == MIPI_DBI_SPI_XFR_16BIT) {
|
||||||
|
ret = mipi_dbi_spi_write_helper_4wire_16bit(
|
||||||
|
dev, dbi_config,
|
||||||
|
cmd_present, cmd,
|
||||||
|
data_buf, len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, unsupported mode */
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
k_mutex_unlock(&data->lock);
|
k_mutex_unlock(&data->lock);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -433,6 +560,7 @@ static DEVICE_API(mipi_dbi, mipi_dbi_spi_driver_api) = {
|
||||||
DT_INST_PHANDLE(n, spi_dev)), \
|
DT_INST_PHANDLE(n, spi_dev)), \
|
||||||
.cmd_data = GPIO_DT_SPEC_INST_GET_OR(n, dc_gpios, {}), \
|
.cmd_data = GPIO_DT_SPEC_INST_GET_OR(n, dc_gpios, {}), \
|
||||||
.reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \
|
.reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \
|
||||||
|
.xfr_min_bits = DT_INST_PROP(n, xfr_min_bits) \
|
||||||
}; \
|
}; \
|
||||||
static struct mipi_dbi_spi_data mipi_dbi_spi_data_##n; \
|
static struct mipi_dbi_spi_data mipi_dbi_spi_data_##n; \
|
||||||
\
|
\
|
||||||
|
|
|
@ -27,6 +27,22 @@ properties:
|
||||||
description: |
|
description: |
|
||||||
Reset GPIO pin. Set high to reset the display
|
Reset GPIO pin. Set high to reset the display
|
||||||
|
|
||||||
|
xfr-min-bits:
|
||||||
|
type: int
|
||||||
|
default: 8
|
||||||
|
description:
|
||||||
|
On rare types of SPI interfaces, discrete shift registers can be found
|
||||||
|
whose task is to convert the serial SPI bit stream to the parallel MCU
|
||||||
|
interface with clock and bit accuracy. Typically, these are 16 bits wide.
|
||||||
|
|
||||||
|
Use the macros, not the actual enum value. Here is the concordance list
|
||||||
|
(see dt-bindings/mipi_dbi/mipi_dbi.h)
|
||||||
|
8 MIPI_DBI_SPI_XFR_8BIT
|
||||||
|
16 MIPI_DBI_SPI_XFR_16BIT
|
||||||
|
enum:
|
||||||
|
- 8
|
||||||
|
- 16
|
||||||
|
|
||||||
write-only:
|
write-only:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: |
|
description: |
|
||||||
|
|
|
@ -110,6 +110,34 @@
|
||||||
#define MIPI_DBI_MODE_8080_BUS_9_BIT 0x7
|
#define MIPI_DBI_MODE_8080_BUS_9_BIT 0x7
|
||||||
#define MIPI_DBI_MODE_8080_BUS_8_BIT 0x8
|
#define MIPI_DBI_MODE_8080_BUS_8_BIT 0x8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI transfer of DBI commands as 8-bit blocks, the default behaviour in
|
||||||
|
* SPI 4 wire (Type C3) mode. The clocking diagram corresponds exactly to
|
||||||
|
* the illustration of Type C3.
|
||||||
|
*/
|
||||||
|
#define MIPI_DBI_SPI_XFR_8BIT 8
|
||||||
|
/**
|
||||||
|
* SPI transfer of DBI commands as 16-bit blocks, a rare and seldom behaviour
|
||||||
|
* in SPI 4 wire (Type C3) mode. The corresponding clocking diagram is slightly
|
||||||
|
* different to the illustration of Type C3.
|
||||||
|
*
|
||||||
|
* .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-.
|
||||||
|
* SCK -' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '---
|
||||||
|
*
|
||||||
|
* -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.-
|
||||||
|
* DOUT |D15|D14|D13|D12|D11|D10| D9| D8| D7| D6| D5| D4| D3| D2| D1| D0|
|
||||||
|
* -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'-
|
||||||
|
* | Word 1 (stuffing) : (byte) |
|
||||||
|
*
|
||||||
|
* -. .-
|
||||||
|
* CS '---------------------------------------------------------------'
|
||||||
|
*
|
||||||
|
* -.---------------------------------------------------------------.-
|
||||||
|
* CD | D/C |
|
||||||
|
* -'---------------------------------------------------------------'-
|
||||||
|
*/
|
||||||
|
#define MIPI_DBI_SPI_XFR_16BIT 16
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue