From 1faf65d11c1e02c312e3c37bc2d1e35e0a9a6bc9 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Sat, 7 Sep 2024 18:19:52 +0200 Subject: [PATCH] SPI: driver for devices with user-provided bus transfer function --- platform/drivers/SPI/spi_custom.c | 57 ++++++++++++++++++++ platform/drivers/SPI/spi_custom.h | 89 +++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 platform/drivers/SPI/spi_custom.c create mode 100644 platform/drivers/SPI/spi_custom.h diff --git a/platform/drivers/SPI/spi_custom.c b/platform/drivers/SPI/spi_custom.c new file mode 100644 index 00000000..2e61c971 --- /dev/null +++ b/platform/drivers/SPI/spi_custom.c @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include "spi_custom.h" + +int spiCustom_transfer(const struct spiDevice *dev, const void *txBuf, + void *rxBuf, const size_t size) +{ + const struct spiCustomDevice *spiDev = (const struct spiCustomDevice *) dev; + const uint8_t *txData = (const uint8_t *) txBuf; + uint8_t *rxData = (uint8_t *) rxBuf; + + if(spiDev->spiFunc == NULL) + return -EIO; + + // Send only + if(rxBuf == NULL) + { + for(size_t i = 0; i < size; i++) + spiDev->spiFunc(dev->priv, txData[i]); + + return 0; + } + + // Receive only + if(txBuf == NULL) + { + for(size_t i = 0; i < size; i++) + rxData[i] = spiDev->spiFunc(dev->priv, 0x00); + + return 0; + } + + // Transmit and receive, only symmetric transfer is supported + for(size_t i = 0; i < size; i++) + rxData[i] = spiDev->spiFunc(dev->priv, txData[i]); + + return 0; +} diff --git a/platform/drivers/SPI/spi_custom.h b/platform/drivers/SPI/spi_custom.h new file mode 100644 index 00000000..e101ce91 --- /dev/null +++ b/platform/drivers/SPI/spi_custom.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2024 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef SPI_CUSTOM_H +#define SPI_CUSTOM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This module allows to create an SPI device with a custom implementation of + * the bus transfer function. An example usage is to create an SPI device using + * an high-performance bitbanging routine. + */ + +/** + * Transfer single byte on the SPI bus. + * + * @param dev: SPI device handle. + * @param tx: byte to be sent. + * @return byte received from remote device. + */ +typedef uint8_t (*spi_func)(const void *priv, uint8_t tx); + +/** + * Implementation of the SPI transfer function. + * + * @param dev: SPI device handle. + * @param txBuf: pointer to TX buffer, can be NULL. + * @param rxBuf: pointer to RX buffer, can be NULL. + * @param size: number of bytes to transfer. + * @return zero on success, a negative error code otherwise. + */ +int spiCustom_transfer(const struct spiDevice *dev, const void *txBuf, + void *rxBuf, const size_t size); + +/** + * Custom SPI device descriptor. + */ +struct spiCustomDevice +{ + spi_transfer_impl transfer; ///< Device-specific implementation of the SPI transfer function + const void *priv; ///< Pointer to device driver private data + pthread_mutex_t *mutex; ///< Pointer to mutex for exclusive access + spi_func spiFunc; ///< Pointer to driver configuration data. +}; + +/** + * Instantiate a custom SPI device. + * + * @param name: device name. + * @param impl: user-provided implementation of the single byte transfer function. + * @param args: pointer to user-defined arguments. + * @param mutx: pointer to mutex, or NULL. + */ +#define SPI_CUSTOM_DEVICE_DEFINE(name, impl, args, mutx) \ +const struct spiCustomDevice name = \ +{ \ + .transfer = spiCustom_transfer, \ + .priv = args, \ + .mutex = mutx, \ + .spiFunc = impl \ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* SPI_CUSTOM_H */