drv: display: Initial FT800 display driver
This patch includes initial support for FT800 display driver. It includes basic features. It can be easily extended with more FT800 display list and co-processor features. Signed-off-by: Hubert Miś <hubert.mis@gmail.com>
This commit is contained in:
parent
0da8ec70dc
commit
7d8f78a08b
22 changed files with 2346 additions and 0 deletions
202
drivers/misc/ft8xx/ft8xx_drv.c
Normal file
202
drivers/misc/ft8xx/ft8xx_drv.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Hubert Miś
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "ft8xx_drv.h"
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/spi.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#define LOG_MODULE_NAME ft8xx_drv
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
#define DT_DRV_COMPAT ftdi_ft800
|
||||
#define NODE_ID DT_INST(0, DT_DRV_COMPAT)
|
||||
|
||||
/* SPI device */
|
||||
static const struct device *spi_ft8xx_dev;
|
||||
static struct spi_cs_control cs_ctrl;
|
||||
static const struct spi_config spi_cfg = {
|
||||
.frequency = 8000000UL,
|
||||
.operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER,
|
||||
.cs = &cs_ctrl,
|
||||
};
|
||||
|
||||
/* GPIO int line */
|
||||
#define IRQ_PIN DT_GPIO_PIN(NODE_ID, irq_gpios)
|
||||
static const struct device *int_ft8xx_dev;
|
||||
|
||||
static struct gpio_callback irq_cb_data;
|
||||
|
||||
__weak void ft8xx_drv_irq_triggered(const struct device *dev,
|
||||
struct gpio_callback *cb, uint32_t pins)
|
||||
{
|
||||
/* Intentionally empty */
|
||||
}
|
||||
|
||||
/* Protocol details */
|
||||
#define ADDR_SIZE 3
|
||||
#define DUMMY_READ_SIZE 1
|
||||
#define COMMAND_SIZE 3
|
||||
#define MAX_READ_LEN (UINT16_MAX - ADDR_SIZE - DUMMY_READ_SIZE)
|
||||
#define MAX_WRITE_LEN (UINT16_MAX - ADDR_SIZE)
|
||||
|
||||
#define READ_OP 0x00
|
||||
#define WRITE_OP 0x80
|
||||
#define COMMAND_OP 0x40
|
||||
|
||||
static void insert_addr(uint32_t addr, uint8_t *buff)
|
||||
{
|
||||
buff[0] = (addr >> 16) & 0x3f;
|
||||
buff[1] = (addr >> 8) & 0xff;
|
||||
buff[2] = (addr) & 0xff;
|
||||
}
|
||||
|
||||
int ft8xx_drv_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cs_ctrl = (struct spi_cs_control){
|
||||
.gpio_dev = device_get_binding(
|
||||
DT_SPI_DEV_CS_GPIOS_LABEL(NODE_ID)),
|
||||
.gpio_pin = DT_SPI_DEV_CS_GPIOS_PIN(NODE_ID),
|
||||
.gpio_dt_flags = DT_SPI_DEV_CS_GPIOS_FLAGS(NODE_ID),
|
||||
.delay = 0,
|
||||
};
|
||||
|
||||
spi_ft8xx_dev = device_get_binding(DT_BUS_LABEL(NODE_ID));
|
||||
if (!spi_ft8xx_dev) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* TODO: Verify if such entry in DTS is present.
|
||||
* If not, use polling mode.
|
||||
*/
|
||||
int_ft8xx_dev = device_get_binding(DT_GPIO_LABEL(NODE_ID, irq_gpios));
|
||||
if (!int_ft8xx_dev) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure(int_ft8xx_dev, IRQ_PIN,
|
||||
GPIO_INPUT | DT_GPIO_FLAGS(NODE_ID, irq_gpios));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_pin_interrupt_configure(int_ft8xx_dev, IRQ_PIN,
|
||||
GPIO_INT_EDGE_TO_ACTIVE);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_init_callback(&irq_cb_data, ft8xx_drv_irq_triggered, BIT(IRQ_PIN));
|
||||
gpio_add_callback(int_ft8xx_dev, &irq_cb_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft8xx_drv_write(uint32_t address, const uint8_t *data, unsigned int length)
|
||||
{
|
||||
int ret;
|
||||
uint8_t addr_buf[ADDR_SIZE];
|
||||
|
||||
insert_addr(address, addr_buf);
|
||||
addr_buf[0] |= WRITE_OP;
|
||||
|
||||
struct spi_buf tx[] = {
|
||||
{
|
||||
.buf = addr_buf,
|
||||
.len = sizeof(addr_buf),
|
||||
},
|
||||
{
|
||||
/* Discard const, it is implicit for TX buffer */
|
||||
.buf = (uint8_t *)data,
|
||||
.len = length,
|
||||
},
|
||||
};
|
||||
|
||||
struct spi_buf_set tx_bufs = {
|
||||
.buffers = tx,
|
||||
.count = 2,
|
||||
};
|
||||
|
||||
ret = spi_write(spi_ft8xx_dev, &spi_cfg, &tx_bufs);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("SPI write error: %d", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ft8xx_drv_read(uint32_t address, uint8_t *data, unsigned int length)
|
||||
{
|
||||
int ret;
|
||||
uint8_t dummy_read_buf[ADDR_SIZE + DUMMY_READ_SIZE];
|
||||
uint8_t addr_buf[ADDR_SIZE];
|
||||
|
||||
insert_addr(address, addr_buf);
|
||||
addr_buf[0] |= READ_OP;
|
||||
|
||||
struct spi_buf tx = {
|
||||
.buf = addr_buf,
|
||||
.len = sizeof(addr_buf),
|
||||
};
|
||||
|
||||
struct spi_buf_set tx_bufs = {
|
||||
.buffers = &tx,
|
||||
.count = 1,
|
||||
};
|
||||
|
||||
struct spi_buf rx[] = {
|
||||
{
|
||||
.buf = dummy_read_buf,
|
||||
.len = sizeof(dummy_read_buf),
|
||||
},
|
||||
{
|
||||
.buf = data,
|
||||
.len = length,
|
||||
},
|
||||
};
|
||||
|
||||
struct spi_buf_set rx_bufs = {
|
||||
.buffers = rx,
|
||||
.count = 2,
|
||||
};
|
||||
|
||||
ret = spi_transceive(spi_ft8xx_dev, &spi_cfg, &tx_bufs, &rx_bufs);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("SPI transceive error: %d", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ft8xx_drv_command(uint8_t command)
|
||||
{
|
||||
int ret;
|
||||
/* Most commands include COMMAND_OP bit. ACTIVE power mode command is
|
||||
* an exception with value 0x00.
|
||||
*/
|
||||
uint8_t cmd_buf[COMMAND_SIZE] = {command, 0, 0};
|
||||
|
||||
struct spi_buf tx = {
|
||||
.buf = cmd_buf,
|
||||
.len = sizeof(cmd_buf),
|
||||
};
|
||||
|
||||
struct spi_buf_set tx_bufs = {
|
||||
.buffers = &tx,
|
||||
.count = 1,
|
||||
};
|
||||
|
||||
ret = spi_write(spi_ft8xx_dev, &spi_cfg, &tx_bufs);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("SPI command error: %d", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue