Merge pull request #11352 from fhessel/native_spi
cpu/native: Allow Access to Hardware SPI Bus on Linux
This commit is contained in:
commit
31228bc0fe
@ -19,4 +19,5 @@ OS/RIOT/images/Native.jpg)
|
||||
- LEDs: One red and one green LED - state changes are printed to the UART
|
||||
- PWM: Dummy PWM
|
||||
- QDEC: Emulated according to PWM
|
||||
- SPI: Runtime configurable - `/dev/spidev*` are supported (Linux host only)
|
||||
*/
|
||||
|
||||
3
cpu/native/Makefile.dep
Normal file
3
cpu/native/Makefile.dep
Normal file
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter periph_spi,$(USEMODULE)))
|
||||
USEMODULE += periph_spidev_linux
|
||||
endif
|
||||
@ -5,3 +5,8 @@ FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_hwrng
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
FEATURES_PROVIDED += periph_pwm
|
||||
|
||||
# Access to hardware SPI bus is only supported on Linux hosts
|
||||
ifeq ($(OS),Linux)
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
endif
|
||||
|
||||
@ -50,7 +50,6 @@
|
||||
|
||||
/**
|
||||
* @brief xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#define XTIMER_OVERHEAD 14
|
||||
|
||||
@ -86,6 +85,44 @@
|
||||
#define QDEC_NUMOF (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name SPI configuration (Linux host only)
|
||||
* @{
|
||||
*/
|
||||
#if !defined(SPI_NUMOF) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Amount of SPI devices
|
||||
*
|
||||
* Allows up to SPI_NUMOF SPI devices with each having up to SPI_MAXCS hardware
|
||||
* cable select lines. Assignment to hardware devices can be configured at
|
||||
* runtime using the `--spi` startup parameter.
|
||||
*
|
||||
* Can be overriden during compile time with a `-DSPI_NUMOF=n` flag.
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
#endif
|
||||
|
||||
#if !defined(SPI_MAXCS) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Maximum amount of chip select lines per bus
|
||||
*
|
||||
* Allows up to SPI_MAXCS hardware cable select lines per SPI device. The n-th
|
||||
* hardware select line can be used with the SPI_HWCS macro.
|
||||
*/
|
||||
#define SPI_MAXCS (4U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Hardware chip select access macro.
|
||||
*
|
||||
* The amount of available hardware chip select lines depends on the SPI_MAXCS
|
||||
* parameter. If the line is actually available at runtime depends of whether a
|
||||
* `--spi` startup parameter with the corresponding SPI device and HWCS-line
|
||||
* parameter has been given.
|
||||
*/
|
||||
#define SPI_HWCS(x) (x)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -45,6 +45,52 @@ extern "C" {
|
||||
#define PROVIDES_PM_SET_LOWEST
|
||||
/** @} */
|
||||
|
||||
/* Configuration for the wrapper around the Linux SPI API (periph_spidev_linux)
|
||||
*
|
||||
* Needs to go here, otherwise the SPI_NEEDS_ are defined after inclusion of
|
||||
* spi.h.
|
||||
*/
|
||||
#if defined(MODULE_PERIPH_SPIDEV_LINUX) || defined(DOXYGEN)
|
||||
|
||||
/**
|
||||
* @name SPI Configuration
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Use the common `transfer_byte` SPI function
|
||||
*/
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
|
||||
/**
|
||||
* @brief Use the common `transfer_reg` SPI function
|
||||
*/
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REG
|
||||
/**
|
||||
* @brief Use the common `transfer_regs` SPI function
|
||||
*/
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
|
||||
|
||||
/**
|
||||
* @brief Use a custom clock speed type
|
||||
*/
|
||||
#define HAVE_SPI_CLK_T
|
||||
/**
|
||||
* @brief SPI clock speed values
|
||||
*
|
||||
* The Linux userspace driver takes values in Hertz, which values are available
|
||||
* can only be determined at runtime.
|
||||
* @{
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_CLK_100KHZ = (100000U),
|
||||
SPI_CLK_400KHZ = (400000U),
|
||||
SPI_CLK_1MHZ = (1000000U),
|
||||
SPI_CLK_5MHZ = (5000000U),
|
||||
SPI_CLK_10MHZ = (10000000U)
|
||||
} spi_clk_t;
|
||||
/** @} */
|
||||
|
||||
#endif /* MODULE_PERIPH_SPI | DOXYGEN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
134
cpu/native/include/spidev_linux.h
Normal file
134
cpu/native/include/spidev_linux.h
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Frank Hessel <frank@fhessel.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_spidev_linux Linux User Mode SPI Driver
|
||||
* @ingroup cpu_native
|
||||
* @brief Implementation of SPI access from Linux User Space
|
||||
*
|
||||
* This module allows to connect a RIOT application that runs on a Linux host to
|
||||
* the physical SPI bus(ses) of that host. To do so, the application has to be
|
||||
* compiled for the native board in a Linux environment.
|
||||
*
|
||||
* SPI support is automatically included if either a module requiring the
|
||||
* `PERIPH_SPI` feature is added to the application or if it is explicitly
|
||||
* listed as `FEATURES_REQUIRED` in the application's Makefile.
|
||||
*
|
||||
* At runtime, the process has to be connected to a specific bus on the host
|
||||
* machine. SPI busses are exposed as `/dev/spidevB.D` character files, where B
|
||||
* is the Bus ID (MISO, MOSI and SCLK lines) and D denotes the connected device
|
||||
* or hardware chip select line. Ideally, this structure should be reflected
|
||||
* when mapping the device files to RIOT SPI busses.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* $ ./riot_native_app --spi=0:0:/dev/spidev0.0 --spi=0:1:/dev/spidev0.1
|
||||
* ```
|
||||
*
|
||||
* This will add `/dev/spidev0.0` and `/dev/spidev0.1` as SPI_DEV(0) in RIOT.
|
||||
* The first device can be used with SPI_HWCS(0) as CS parameter, the second one
|
||||
* with SPI_HWCS(1) as CS parameter.
|
||||
*
|
||||
* Multiple SPI busses can be added by increasing SPI_NUMOF in the Makefile:
|
||||
* ```
|
||||
* CFLAGS += -DSPI_NUMOF=n
|
||||
* ```
|
||||
*
|
||||
* The sames goes for the SPI_MAXCS parameter that defines the maximum number of
|
||||
* SPI_HWCS values per bus.
|
||||
*
|
||||
* Busses that aren't assigned during startup will return either SPI_NODEV or
|
||||
* SPI_NOCS when accessed.
|
||||
*
|
||||
* If the SPI API is called with SPI_CS_UNDEF as CS parameter, the driver will
|
||||
* select the file descriptor with the lowest HWCS id for that bus, but the
|
||||
* actual CS line will not be pulled low (if the hardware supports this). This
|
||||
* would (in principle) allow to control CS manually.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of SPI access from Linux User Space
|
||||
*
|
||||
* @author Frank Hessel <frank@fhessel.de>
|
||||
*/
|
||||
|
||||
#ifndef SPIDEV_LINUX_H
|
||||
#define SPIDEV_LINUX_H
|
||||
|
||||
#if defined(__linux__) || defined(DOXYGEN) /* Linux-only */
|
||||
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "mutex.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Status codes for SPI device setup
|
||||
*/
|
||||
enum {
|
||||
SPI_SETUP_OK = 0, /**< parameters are sound */
|
||||
SPI_SETUP_INVALID = -1, /**< invalid params or duplicate definition */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Static runtime configuration for SPI port + CS line
|
||||
*
|
||||
* Contains the information that is passed by command line on startup
|
||||
*/
|
||||
typedef struct spidev_linux_conf {
|
||||
/** Filename for a specific SPI device + CS line (like /dev/spidev0.0) */
|
||||
char *device_filename[SPI_MAXCS];
|
||||
} spidev_linux_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Dynamic runtime state for SPI port + CS line
|
||||
*
|
||||
* Contains state of the line (whether if it's opened, in use, available, ...)
|
||||
*/
|
||||
typedef struct spidev_linux_state {
|
||||
/** Mutex for the whole bus (all CS lines) */
|
||||
mutex_t lock;
|
||||
/** File descriptors for each CS line on the bus */
|
||||
int fd[SPI_MAXCS];
|
||||
} spidev_linux_state_t;
|
||||
|
||||
/**
|
||||
* @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] 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);
|
||||
|
||||
/**
|
||||
* @brief Close open SPI file descriptors
|
||||
*/
|
||||
void spidev_linux_teardown(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* Create the error in the header file as spi.c will be compiled to late to show it */
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
#error "MODULE periph_spidev_linux is only available on Linux"
|
||||
#endif
|
||||
#endif /* defined(__linux__) || defined(DOXYGEN) */
|
||||
|
||||
#endif /* SPIDEV_LINUX_H */
|
||||
/** @} */
|
||||
@ -26,6 +26,11 @@
|
||||
#include "async_read.h"
|
||||
#include "tty_uart.h"
|
||||
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
/* Only manage SPI if it is part of the build */
|
||||
#include "spidev_linux.h"
|
||||
#endif
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
@ -44,6 +49,9 @@ void pm_set_lowest(void)
|
||||
void pm_off(void)
|
||||
{
|
||||
puts("\nnative: exiting");
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
spidev_linux_teardown();
|
||||
#endif
|
||||
real_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@ -52,6 +60,9 @@ void pm_reboot(void)
|
||||
printf("\n\n\t\t!! REBOOT !!\n\n");
|
||||
|
||||
native_async_read_cleanup();
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
spidev_linux_teardown();
|
||||
#endif
|
||||
|
||||
if (real_execve(_native_argv[0], _native_argv, NULL) == -1) {
|
||||
err(EXIT_FAILURE, "reboot: execve");
|
||||
|
||||
274
cpu/native/periph/spidev_linux.c
Normal file
274
cpu/native/periph/spidev_linux.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Frank Hessel <frank@fhessel.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup cpu_native
|
||||
* @ingroup drivers_spidev_linux
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of SPI access from Linux User Space
|
||||
*
|
||||
* @author Frank Hessel <frank@fhessel.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
/* Linux' SPI_MODE_N collide with RIOT's spi_mode_t enum */
|
||||
#undef SPI_MODE_0
|
||||
#undef SPI_MODE_1
|
||||
#undef SPI_MODE_2
|
||||
#undef SPI_MODE_3
|
||||
|
||||
#include "assert.h"
|
||||
#include "native_internal.h"
|
||||
#include "spidev_linux.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Holds the configuration for each SPI device (pathnames)
|
||||
*/
|
||||
static spidev_linux_conf_t device_conf[SPI_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Holds the current state for each SPI device (file descriptors, mutex)
|
||||
*/
|
||||
static spidev_linux_state_t device_state[SPI_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Returns the fd of the first valid cs line
|
||||
*/
|
||||
static int spidev_get_first_fd(spidev_linux_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Initializes a spidev_linux_state_t structure
|
||||
*/
|
||||
static void spidev_init_device_state(spidev_linux_state_t *state);
|
||||
|
||||
/**
|
||||
* @brief Applies bus parameters
|
||||
*
|
||||
* @param[in] fd File descriptor for the bus
|
||||
* @param[in] hwcs true if the hardware chip select line should be used
|
||||
* @param[in] mode SPI mode (0..3)
|
||||
* @param[in] clk Clock rate in Hertz
|
||||
*
|
||||
* @return SPI_OK If everything went well
|
||||
* @return SPI_NOMODE If setting the mode didn't work
|
||||
* @return SPI_NOCLK If setting the clock didn't work
|
||||
*/
|
||||
static int spi_set_params(int fd, bool hwcs, spi_mode_t mode, spi_clk_t clk);
|
||||
|
||||
static void spidev_init_device_state(spidev_linux_state_t *state)
|
||||
{
|
||||
mutex_init(&(state->lock));
|
||||
for (spi_cs_t cs = 0; cs < SPI_MAXCS; cs++) {
|
||||
state->fd[cs] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int spidev_get_first_fd(spidev_linux_state_t *state)
|
||||
{
|
||||
int fd = -1;
|
||||
|
||||
for (spi_cs_t cs = 0; cs < SPI_MAXCS && fd < 0; cs++) {
|
||||
fd = state->fd[cs];
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int spidev_linux_setup(spi_t bus, spi_cs_t cs, const char *name)
|
||||
{
|
||||
if (bus >= SPI_NUMOF || cs >= SPI_MAXCS) {
|
||||
return SPI_SETUP_INVALID;
|
||||
}
|
||||
spidev_linux_conf_t *conf = &(device_conf[bus]);
|
||||
if (conf->device_filename[cs] != NULL) {
|
||||
return SPI_SETUP_INVALID;
|
||||
}
|
||||
device_conf[bus].device_filename[cs] = strndup(name, PATH_MAX - 1);
|
||||
return SPI_SETUP_OK;
|
||||
}
|
||||
|
||||
void spidev_linux_teardown(void)
|
||||
{
|
||||
for (spi_t bus = 0; bus < SPI_NUMOF; bus++) {
|
||||
spidev_linux_state_t *state = &(device_state[bus]);
|
||||
for (spi_cs_t cs = 0; cs < SPI_MAXCS; cs++) {
|
||||
if (state->fd[cs] >= 0) {
|
||||
real_close(state->fd[cs]);
|
||||
}
|
||||
}
|
||||
spidev_init_device_state(state);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (bus >= SPI_NUMOF) {
|
||||
return SPI_NODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&(device_state[bus].lock));
|
||||
|
||||
bool use_hwcs = false;
|
||||
int fd = -1;
|
||||
if (cs != SPI_CS_UNDEF) {
|
||||
use_hwcs = true;
|
||||
if (cs > SPI_MAXCS || device_state[bus].fd[cs] < 0) {
|
||||
DEBUG("spi_acquire: No fd for %d:%d\n", bus, cs);
|
||||
return SPI_NOCS;
|
||||
}
|
||||
fd = device_state[bus].fd[cs];
|
||||
DEBUG("spi_acquire: Using %d:%d with HWCS (-> fd 0x%x)\n", bus, cs, fd);
|
||||
}
|
||||
else {
|
||||
fd = spidev_get_first_fd(&(device_state[bus]));
|
||||
if (fd < 0) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
DEBUG("spi_acquire: Using SPI_NO_CS (-> fd 0x%x)\n", fd);
|
||||
}
|
||||
|
||||
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);
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
}
|
||||
|
||||
DEBUG("spi_acquire: %d:%d acquired\n", bus, cs);
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
assert(bus < SPI_NUMOF);
|
||||
spidev_linux_state_t *state = &(device_state[bus]);
|
||||
spidev_linux_conf_t *conf = &(device_conf[bus]);
|
||||
|
||||
spidev_init_device_state(state);
|
||||
DEBUG("spi_init: init bus %d\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",
|
||||
conf->device_filename[cs],
|
||||
bus,
|
||||
cs
|
||||
);
|
||||
assert(false);
|
||||
}
|
||||
DEBUG("spi_init: %d:%d %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: done\n");
|
||||
}
|
||||
|
||||
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) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
else if (device_state[bus].fd[cs] < 0) {
|
||||
return SPI_NOCS;
|
||||
}
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
(void)bus;
|
||||
/* Nothing to do here, as the kernel driver does the pin management */
|
||||
}
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
DEBUG("spi_release(%d)\n", bus);
|
||||
if (bus < SPI_NUMOF) {
|
||||
mutex_unlock(&(device_state[bus].lock));
|
||||
}
|
||||
}
|
||||
|
||||
static int spi_set_params(int fd, bool hwcs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
uint8_t spi_mode = mode | (hwcs ? 0 : SPI_NO_CS);
|
||||
uint32_t ioctl_clk = clk;
|
||||
|
||||
if (real_ioctl(fd, SPI_IOC_WR_MODE, &spi_mode) < 0) {
|
||||
return SPI_NOMODE;
|
||||
}
|
||||
if (real_ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &ioctl_clk) < 0) {
|
||||
return SPI_NOCLK;
|
||||
}
|
||||
return SPI_OK;
|
||||
}
|
||||
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = (cs == SPI_CS_UNDEF) ?
|
||||
spidev_get_first_fd(&(device_state[bus])) :
|
||||
device_state[bus].fd[cs];
|
||||
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
intptr_t out_addr = (intptr_t)out;
|
||||
intptr_t in_addr = (intptr_t)in;
|
||||
|
||||
struct spi_ioc_transfer spi_tf = {
|
||||
.bits_per_word = 8,
|
||||
/*
|
||||
* The kernel documentation is a bit ambiguous about how to use the
|
||||
* cs_change value ("True to deselect device"). It seems like
|
||||
* setting it to true leaves the CS line actually low (=selected)
|
||||
* after transmission.
|
||||
*/
|
||||
.cs_change = cont,
|
||||
.len = len,
|
||||
.rx_buf = (uint64_t)in_addr,
|
||||
.tx_buf = (uint64_t)out_addr,
|
||||
/* Leaving speed_hz as zero uses the value from spi_acquire */
|
||||
.speed_hz = 0,
|
||||
};
|
||||
|
||||
if (real_ioctl(fd, SPI_IOC_MESSAGE(1), &spi_tf) < 0) {
|
||||
DEBUG("spi_transfer_bytes: ioctl failed\n");
|
||||
}
|
||||
else {
|
||||
DEBUG("\nspi_transfer_bytes: transfered %d bytes\n", len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MODULE_PERIPH_SPIDEV_LINUX */
|
||||
@ -76,7 +76,9 @@ netdev_tap_params_t netdev_tap_params[NETDEV_TAP_MAX];
|
||||
#ifdef MODULE_CAN_LINUX
|
||||
#include "candev_linux.h"
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
#include "spidev_linux.h"
|
||||
#endif
|
||||
#ifdef MODULE_SOCKET_ZEP
|
||||
#include "socket_zep_params.h"
|
||||
|
||||
@ -92,6 +94,9 @@ static const char short_opts[] = ":hi:s:deEoc:"
|
||||
#endif
|
||||
#ifdef MODULE_SOCKET_ZEP
|
||||
"z:"
|
||||
#endif
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
"p:"
|
||||
#endif
|
||||
"";
|
||||
|
||||
@ -112,6 +117,9 @@ static const struct option long_opts[] = {
|
||||
#endif
|
||||
#ifdef MODULE_SOCKET_ZEP
|
||||
{ "zep", required_argument, NULL, 'z' },
|
||||
#endif
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
{ "spi", required_argument, NULL, 'p' },
|
||||
#endif
|
||||
{ NULL, 0, NULL, '\0' },
|
||||
};
|
||||
@ -251,6 +259,9 @@ void usage_exit(int status)
|
||||
real_printf(" -z <laddr>:<lport>,<raddr>:<rport>\n");
|
||||
}
|
||||
#endif
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
real_printf(" [-p <b>:<d>:<spidev>]\n");
|
||||
#endif
|
||||
|
||||
real_printf(" help: %s -h\n\n", _progname);
|
||||
|
||||
@ -292,6 +303,15 @@ void usage_exit(int status)
|
||||
" -n <ifnum>:<ifname>, --can <ifnum>:<ifname>\n"
|
||||
" specify CAN interface <ifname> to use for CAN device #<ifnum>\n"
|
||||
" max number of CAN device: %d\n", CAN_DLL_NUMOF);
|
||||
#endif
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
real_printf(
|
||||
" -p <b>:<d>:<spidev>, --spi=<b>:<d>:<spidev>\n"
|
||||
" specify Linux SPI device to use for CS line d on bus b (in RIOT)\n"
|
||||
" Example: --spi=0:1:/dev/spidev0.0 will assign the file spidev0.0 to\n"
|
||||
" SPI_DEV(0) and SPI_HWCS(1).\n"
|
||||
" Supports up to %d busses with %d CS lines each.\n", SPI_NUMOF, SPI_MAXCS
|
||||
);
|
||||
#endif
|
||||
real_exit(status);
|
||||
}
|
||||
@ -455,6 +475,22 @@ __attribute__((constructor)) static void startup(int argc, char **argv, char **e
|
||||
case 'z':
|
||||
_zep_params_setup(optarg, zeps++);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MODULE_PERIPH_SPIDEV_LINUX
|
||||
case 'p': {
|
||||
long bus = strtol(optarg, &optarg, 10);
|
||||
if (*optarg != ':') {
|
||||
usage_exit(EXIT_FAILURE);
|
||||
}
|
||||
long cs = strtol(++optarg, &optarg, 10);
|
||||
if (*optarg != ':') {
|
||||
usage_exit(EXIT_FAILURE);
|
||||
}
|
||||
if (spidev_linux_setup(bus, cs, ++optarg) < 0) {
|
||||
usage_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage_exit(EXIT_FAILURE);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user