mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 04:52:59 +01:00
cpu/native: Adapt HW SPI for HW GPIO support
This commit is contained in:
parent
ea25e8580c
commit
4275b36cdb
@ -111,7 +111,7 @@ extern "C" {
|
||||
* `--spi` startup parameter with the corresponding SPI device and HWCS-line
|
||||
* parameter has been given.
|
||||
*/
|
||||
#define SPI_HWCS(x) (x)
|
||||
#define SPI_HWCS(x) (UINT_MAX - SPI_MAXCS + x)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -107,12 +107,12 @@ typedef struct spidev_linux_state {
|
||||
* @brief register `/dev/spidev*` device to be used for SPI
|
||||
*
|
||||
* @param[in] bus SPI bus id of the device
|
||||
* @param[in] cs CS line to configure
|
||||
* @param[in] cs_id ID of CS line to configure
|
||||
* @param[in] name path name for `/dev/spidev*` device
|
||||
* @return SPI_SETUP_OK On success
|
||||
* @return SPI_SETUP_INVALID On invalid parameters
|
||||
*/
|
||||
int spidev_linux_setup(spi_t bus, spi_cs_t cs, const char *name);
|
||||
int spidev_linux_setup(spi_t bus, unsigned cs_id, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Close open SPI file descriptors
|
||||
|
@ -35,10 +35,38 @@
|
||||
#include "assert.h"
|
||||
#include "native_internal.h"
|
||||
#include "spidev_linux.h"
|
||||
#ifdef MODULE_PERIPH_GPIO
|
||||
#include "periph/gpio.h"
|
||||
#endif
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief true, if x is a hardware-based chip select line
|
||||
*/
|
||||
#define IS_HW_CS(x) (x < UINT_MAX && x >= UINT_MAX - SPI_MAXCS )
|
||||
|
||||
/**
|
||||
* @brief true, if x is a gpio-based chip select line
|
||||
*/
|
||||
#ifdef MODULE_PERIPH_GPIO
|
||||
#define IS_GPIO_CS(x) (x < UINT_MAX - SPI_MAXCS)
|
||||
#else
|
||||
#define IS_GPIO_CS(x) (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief true, if x is a valid chip select line (either GPIO or HW)
|
||||
*/
|
||||
#define IS_VALID_CS(x) (IS_HW_CS(x) || IS_GPIO_CS(x))
|
||||
|
||||
/**
|
||||
* @brief If IS_HW_CS(x), this converts x to the corresponding CS ID for file
|
||||
* descriptor selection, basically a reverse SPI_HWCS(x)
|
||||
*/
|
||||
#define CS_TO_CSID(x) (x - (UINT_MAX - SPI_MAXCS))
|
||||
|
||||
/**
|
||||
* @brief Holds the configuration for each SPI device (pathnames)
|
||||
*/
|
||||
@ -91,16 +119,16 @@ static int spidev_get_first_fd(spidev_linux_state_t *state)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int spidev_linux_setup(spi_t bus, spi_cs_t cs, const char *name)
|
||||
int spidev_linux_setup(spi_t bus, unsigned cs_id, const char *name)
|
||||
{
|
||||
if (bus >= SPI_NUMOF || cs >= SPI_MAXCS) {
|
||||
if (bus >= SPI_NUMOF || cs_id >= SPI_MAXCS) {
|
||||
return SPI_SETUP_INVALID;
|
||||
}
|
||||
spidev_linux_conf_t *conf = &(device_conf[bus]);
|
||||
if (conf->device_filename[cs] != NULL) {
|
||||
if (conf->device_filename[cs_id] != NULL) {
|
||||
return SPI_SETUP_INVALID;
|
||||
}
|
||||
device_conf[bus].device_filename[cs] = strndup(name, PATH_MAX - 1);
|
||||
device_conf[bus].device_filename[cs_id] = strndup(name, PATH_MAX - 1);
|
||||
return SPI_SETUP_OK;
|
||||
}
|
||||
|
||||
@ -119,39 +147,52 @@ void spidev_linux_teardown(void)
|
||||
|
||||
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
DEBUG("spi_acquire(%d, %d, 0x%02x, %d)\n", bus, cs, mode, clk);
|
||||
DEBUG("spi_acquire(%u, %u, 0x%02x, %d)\n", bus, cs, mode, clk);
|
||||
if (bus >= SPI_NUMOF) {
|
||||
return SPI_NODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&(device_state[bus].lock));
|
||||
|
||||
/* If true, the spidev API controls the chip select line. We need this here
|
||||
* if an SPI_HWCS parameter is used. If cs==SPI_CS_UNDEF, the driver should
|
||||
* not care about CS at all (use_hwcs=true), if cs is a GPIO_PIN and the
|
||||
* GPIO module is enabled, the driver controls the pin through that module.
|
||||
*/
|
||||
bool use_hwcs = false;
|
||||
int fd = -1;
|
||||
if (cs != SPI_CS_UNDEF) {
|
||||
if (IS_HW_CS(cs)) {
|
||||
use_hwcs = true;
|
||||
if (cs > SPI_MAXCS || device_state[bus].fd[cs] < 0) {
|
||||
DEBUG("spi_acquire: No fd for %d:%d\n", bus, cs);
|
||||
unsigned csid = CS_TO_CSID(cs);
|
||||
if (device_state[bus].fd[csid] < 0) {
|
||||
DEBUG("spi_acquire: No fd for %u:%u\n", bus, csid);
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
return SPI_NOCS;
|
||||
}
|
||||
fd = device_state[bus].fd[cs];
|
||||
DEBUG("spi_acquire: Using %d:%d with HWCS (-> fd 0x%x)\n", bus, cs, fd);
|
||||
fd = device_state[bus].fd[csid];
|
||||
DEBUG("spi_acquire: Using %u:%u with HWCS (-> fd 0x%x)\n", bus, csid, fd);
|
||||
}
|
||||
else {
|
||||
else if (IS_GPIO_CS(cs) || cs == SPI_CS_UNDEF) {
|
||||
fd = spidev_get_first_fd(&(device_state[bus]));
|
||||
if (fd < 0) {
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
return SPI_NOCS;
|
||||
}
|
||||
DEBUG("spi_acquire: Using SPI_NO_CS (-> fd 0x%x)\n", fd);
|
||||
DEBUG("spi_acquire: Using SPI_CS_UNDEF (-> fd 0x%x)\n", fd);
|
||||
}
|
||||
else {
|
||||
DEBUG("spi_acquire: Invalid CS parameter\n");
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
return SPI_NOCS;
|
||||
}
|
||||
|
||||
int res = spi_set_params(fd, use_hwcs, mode, clk);
|
||||
if (res < 0) {
|
||||
DEBUG("spi_acquire: set_params failed for %d:%d\n", bus, cs);
|
||||
DEBUG("spi_acquire: set_params failed\n");
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
}
|
||||
|
||||
DEBUG("spi_acquire: %d:%d acquired\n", bus, cs);
|
||||
DEBUG("spi_acquire: bus %u acquired\n", bus);
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
@ -162,26 +203,26 @@ void spi_init(spi_t bus)
|
||||
spidev_linux_conf_t *conf = &(device_conf[bus]);
|
||||
|
||||
spidev_init_device_state(state);
|
||||
DEBUG("spi_init: init bus %d\n", bus);
|
||||
DEBUG("spi_init: init bus %u\n", bus);
|
||||
for (spi_cs_t cs = 0; cs < SPI_MAXCS; cs++) {
|
||||
if (conf->device_filename[cs] != NULL) {
|
||||
int fd = real_open(conf->device_filename[cs], O_RDWR);
|
||||
if (fd < 0) {
|
||||
/* Add a printf instead of only asserting to show invalid bus */
|
||||
real_printf(
|
||||
"Cannot acquire %s for spidev%d:%d\n",
|
||||
"Cannot acquire %s for spidev%u:%u\n",
|
||||
conf->device_filename[cs],
|
||||
bus,
|
||||
cs
|
||||
);
|
||||
assert(false);
|
||||
}
|
||||
DEBUG("spi_init: %d:%d %s (fd 0x%x)\n", bus, cs,
|
||||
DEBUG("spi_init: %u:%u %s (fd 0x%x)\n", bus, cs,
|
||||
conf->device_filename[cs], fd);
|
||||
state->fd[cs] = fd;
|
||||
}
|
||||
else {
|
||||
DEBUG("spi_init: %d:%d Unused\n", bus, cs);
|
||||
DEBUG("spi_init: %u:%u Unused\n", bus, cs);
|
||||
}
|
||||
}
|
||||
DEBUG("spi_init: done\n");
|
||||
@ -192,12 +233,20 @@ int spi_init_cs(spi_t bus, spi_cs_t cs)
|
||||
if (bus >= SPI_NUMOF) {
|
||||
return SPI_NODEV;
|
||||
}
|
||||
else if (cs != SPI_CS_UNDEF && cs >= SPI_MAXCS) {
|
||||
else if (!IS_VALID_CS(cs) && cs != SPI_CS_UNDEF) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
else if (device_state[bus].fd[cs] < 0) {
|
||||
else if (IS_HW_CS(cs) && device_state[bus].fd[CS_TO_CSID(cs)] < 0) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
else if (IS_GPIO_CS(cs)) {
|
||||
#ifdef MODULE_PERIPH_GPIO
|
||||
if (gpio_init(cs, GPIO_OUT) < 0) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
gpio_set(cs);
|
||||
#endif
|
||||
}
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
@ -209,7 +258,7 @@ void spi_init_pins(spi_t bus)
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
DEBUG("spi_release(%d)\n", bus);
|
||||
DEBUG("spi_release(%u)\n", bus);
|
||||
if (bus < SPI_NUMOF) {
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
}
|
||||
@ -232,15 +281,17 @@ static int spi_set_params(int fd, bool hwcs, spi_mode_t mode, spi_clk_t clk)
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
if (bus >= SPI_NUMOF || (cs != SPI_CS_UNDEF && cs >= SPI_MAXCS)) {
|
||||
if (bus >= SPI_NUMOF || (!IS_VALID_CS(cs) && cs != SPI_CS_UNDEF)) {
|
||||
DEBUG("spi_transfer_bytes: invalid bus/cs. Skipping transfer.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = (cs == SPI_CS_UNDEF) ?
|
||||
spidev_get_first_fd(&(device_state[bus])) :
|
||||
device_state[bus].fd[cs];
|
||||
int fd = IS_HW_CS(cs) ?
|
||||
device_state[bus].fd[CS_TO_CSID(cs)] :
|
||||
spidev_get_first_fd(&(device_state[bus]));
|
||||
|
||||
if (fd < 0) {
|
||||
DEBUG("spi_transfer_bytes: no suitable fd. Skipping transfer.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -263,12 +314,25 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
.speed_hz = 0,
|
||||
};
|
||||
|
||||
#ifdef MODULE_PERIPH_GPIO
|
||||
if (IS_GPIO_CS(cs)) {
|
||||
DEBUG("spi_transfer_bytes: using GPIO-based CS\n");
|
||||
gpio_clear(cs);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (real_ioctl(fd, SPI_IOC_MESSAGE(1), &spi_tf) < 0) {
|
||||
DEBUG("spi_transfer_bytes: ioctl failed\n");
|
||||
}
|
||||
else {
|
||||
DEBUG("\nspi_transfer_bytes: transferred %d bytes\n", len);
|
||||
DEBUG("spi_transfer_bytes: transferred %u bytes\n", len);
|
||||
}
|
||||
|
||||
#ifdef MODULE_PERIPH_GPIO
|
||||
if (IS_GPIO_CS(cs) && !cont) {
|
||||
gpio_set(cs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* MODULE_PERIPH_SPIDEV_LINUX */
|
||||
|
Loading…
Reference in New Issue
Block a user