sk6812d/src/hat_spi.c

130 lines
3.0 KiB
C

#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/spi/spidev.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include "logger.h"
#include "hat_spi.h"
static const char *spi_dev = "/dev/spidev0.0";
static const uint32_t spi_speed = 12000000; // clock freq in Hz
static const uint16_t spi_delay = 0; // us
static const uint8_t spi_bits = 8; // bits per word
int hat_spi_init(struct hat_spi_ctx *ctx)
{
// Initialize SPI
uint8_t spi_mode = 0;
ctx->spidev_fd = open(spi_dev, O_RDWR);
if(ctx->spidev_fd < 0) {
LOG(LVL_ERR, "hat_spi: cannot open %s: %s", spi_dev, strerror(errno));
return -1;
}
if(ioctl(ctx->spidev_fd, SPI_IOC_WR_MODE, &spi_mode) == -1) {
LOG(LVL_ERR, "hat_spi: cannot change SPI mode: %s", strerror(errno));
return -1;
}
if(ioctl(ctx->spidev_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits) == -1) {
LOG(LVL_ERR, "hat_spi: cannot change SPI bits per word: %s", strerror(errno));
return -1;
}
if(ioctl(ctx->spidev_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) == -1) {
LOG(LVL_ERR, "hat_spi: cannot change SPI speed: %s", strerror(errno));
return -1;
}
return 0;
}
int hat_spi_set_data(struct hat_spi_ctx *ctx, uint8_t strip, size_t len, uint8_t *data)
{
uint8_t message[4 + len];
message[0] = 0x02; // cmd
message[1] = strip; // buffer index
message[2] = 0x00; // start offset (LSB)
message[3] = 0x00; // start offset (MSB)
memcpy(message + 4, data, len);
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)message,
.rx_buf = (unsigned long)NULL,
.len = sizeof(message),
.delay_usecs = spi_delay,
.speed_hz = spi_speed,
.bits_per_word = 8
};
int ret;
if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) {
LOG(LVL_ERR, "ws2801: set_data: could not send SPI message: %s", strerror(errno));
}
return ret;
}
int hat_spi_flush(struct hat_spi_ctx *ctx)
{
uint8_t message[1];
message[0] = 0x80; // cmd
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)message,
.rx_buf = (unsigned long)NULL,
.len = sizeof(message),
.delay_usecs = spi_delay,
.speed_hz = spi_speed,
.bits_per_word = 8
};
int ret;
if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) {
LOG(LVL_ERR, "ws2801: flush: could not send SPI message: %s", strerror(errno));
}
return ret;
}
int hat_spi_config(struct hat_spi_ctx *ctx, uint16_t data_len)
{
uint8_t message[3];
message[0] = 0x01; // cmd
message[1] = data_len & 0xFF; // bytes per strip (LSB)
message[2] = (data_len >> 8) & 0xFF; // bytes per strip (MSB)
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)message,
.rx_buf = (unsigned long)NULL,
.len = sizeof(message),
.delay_usecs = spi_delay,
.speed_hz = spi_speed,
.bits_per_word = 8
};
int ret;
if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) {
LOG(LVL_ERR, "ws2801: flush: could not send SPI message: %s", strerror(errno));
}
return ret;
}
void hat_spi_shutdown(struct hat_spi_ctx *ctx)
{
close(ctx->spidev_fd);
}