1
0
Fork 0
forked from nuttx/nuttx-update

driver/spi_slave: support spi_slave asynchronous

1. support spi slave device poll
2. support read non-block/block mode

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1 2023-03-30 13:47:58 +08:00 committed by Petro Karashchenko
parent abc1cade35
commit 9bf66ba3d5
2 changed files with 193 additions and 25 deletions

View file

@ -33,6 +33,8 @@
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <fcntl.h>
#include <poll.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
@ -40,8 +42,6 @@
#include <nuttx/semaphore.h>
#include <nuttx/spi/slave.h>
#ifdef CONFIG_SPI_SLAVE_DRIVER
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -64,7 +64,15 @@ struct spi_slave_driver_s
/* Reference to SPI Slave controller interface */
struct spi_slave_ctrlr_s *ctrlr;
FAR struct spi_slave_ctrlr_s *ctrlr;
/* The poll waiter */
FAR struct pollfd *fds;
/* The semphore reader */
sem_t wait;
/* Receive buffer */
@ -75,9 +83,9 @@ struct spi_slave_driver_s
uint8_t tx_buffer[CONFIG_SPI_SLAVE_DRIVER_BUFFER_SIZE];
uint32_t tx_length; /* Location of next TX value */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
mutex_t lock; /* Mutual exclusion */
int16_t crefs; /* Number of open references */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
bool unlinked; /* Indicates if the driver has been unlinked */
#endif
};
@ -94,18 +102,22 @@ static ssize_t spi_slave_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t spi_slave_write(FAR struct file *filep,
FAR const char *buffer, size_t buflen);
static int spi_slave_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup);
static int spi_slave_unlink(FAR struct inode *inode);
/* SPI Slave driver methods */
static void spi_slave_select(FAR struct spi_slave_dev_s *sdev,
static void spi_slave_select(FAR struct spi_slave_dev_s *dev,
bool selected);
static void spi_slave_cmddata(FAR struct spi_slave_dev_s *sdev,
static void spi_slave_cmddata(FAR struct spi_slave_dev_s *dev,
bool data);
static size_t spi_slave_getdata(FAR struct spi_slave_dev_s *sdev,
static size_t spi_slave_getdata(FAR struct spi_slave_dev_s *dev,
FAR const void **data);
static size_t spi_slave_receive(FAR struct spi_slave_dev_s *sdev,
static size_t spi_slave_receive(FAR struct spi_slave_dev_s *dev,
FAR const void *data, size_t nwords);
static void spi_slave_notify(FAR struct spi_slave_dev_s *dev,
spi_slave_state_t state);
/****************************************************************************
* Private Data
@ -113,20 +125,15 @@ static size_t spi_slave_receive(FAR struct spi_slave_dev_s *sdev,
static const struct file_operations g_spislavefops =
{
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
spi_slave_open, /* open */
spi_slave_close, /* close */
#else
NULL, /* open */
NULL, /* close */
#endif
spi_slave_read, /* read */
spi_slave_write, /* write */
NULL, /* seek */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* truncate */
NULL /* poll */
spi_slave_poll /* poll */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
, spi_slave_unlink /* unlink */
#endif
@ -138,6 +145,7 @@ static const struct spi_slave_devops_s g_spisdev_ops =
spi_slave_cmddata, /* cmddata */
spi_slave_getdata, /* getdata */
spi_slave_receive, /* receive */
spi_slave_notify, /* notify */
};
/****************************************************************************
@ -159,7 +167,6 @@ static const struct spi_slave_devops_s g_spisdev_ops =
*
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int spi_slave_open(FAR struct file *filep)
{
FAR struct inode *inode;
@ -194,7 +201,6 @@ static int spi_slave_open(FAR struct file *filep)
nxmutex_unlock(&priv->lock);
return OK;
}
#endif
/****************************************************************************
* Name: spi_slave_close
@ -211,7 +217,6 @@ static int spi_slave_open(FAR struct file *filep)
*
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int spi_slave_close(FAR struct file *filep)
{
FAR struct inode *inode;
@ -247,7 +252,11 @@ static int spi_slave_close(FAR struct file *filep)
* unlinked, then dispose of the driver resources.
*/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
if (priv->crefs <= 0 && priv->unlinked)
#else
if (priv->crefs <= 0)
#endif
{
nxmutex_destroy(&priv->lock);
kmm_free(priv);
@ -258,7 +267,6 @@ static int spi_slave_close(FAR struct file *filep)
nxmutex_unlock(&priv->lock);
return OK;
}
#endif
/****************************************************************************
* Name: spi_slave_read
@ -285,6 +293,7 @@ static ssize_t spi_slave_read(FAR struct file *filep, FAR char *buffer,
FAR struct spi_slave_driver_s *priv;
size_t read_bytes;
size_t remaining_words;
int ret;
spiinfo("filep=%p buffer=%p buflen=%zu\n", filep, buffer, buflen);
@ -300,20 +309,54 @@ static ssize_t spi_slave_read(FAR struct file *filep, FAR char *buffer,
}
priv->rx_length = MIN(buflen, sizeof(priv->rx_buffer));
remaining_words = SPIS_CTRLR_QPOLL(priv->ctrlr);
if (remaining_words == 0)
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
spiinfo("All words retrieved!\n");
spierr("Failed to get exclusive access: %d\n", ret);
return ret;
}
else
do
{
spiinfo("%zu words left in the buffer\n", remaining_words);
remaining_words = SPIS_CTRLR_QPOLL(priv->ctrlr);
if (remaining_words == 0)
{
spiinfo("All words retrieved!\n");
}
else
{
spiinfo("%zu words left in the buffer\n", remaining_words);
}
if (priv->rx_length == 0)
{
nxmutex_unlock(&priv->lock);
if (filep->f_oflags & O_NONBLOCK)
{
return -EAGAIN;
}
ret = nxsem_wait(&priv->wait);
if (ret < 0)
{
return ret;
}
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
spierr("Failed to get exclusive access: %d\n", ret);
return ret;
}
}
}
while (priv->rx_length == 0);
read_bytes = MIN(buflen, priv->rx_length);
memcpy(buffer, priv->rx_buffer, read_bytes);
nxmutex_unlock(&priv->lock);
return (ssize_t)read_bytes;
}
@ -363,6 +406,66 @@ static ssize_t spi_slave_write(FAR struct file *filep,
return (ssize_t)enqueued_bytes;
}
/****************************************************************************
* Name: spi_slave_poll
****************************************************************************/
static int spi_slave_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup)
{
FAR struct spi_slave_driver_s *priv;
FAR struct inode *inode;
int ret;
/* Get our private data structure */
inode = filep->f_inode;
priv = (FAR struct spi_slave_driver_s *)inode->i_private;
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
spierr("Failed to get exclusive access: %d\n", ret);
return ret;
}
if (setup)
{
pollevent_t eventset = 0;
if (priv->fds == NULL)
{
priv->fds = fds;
fds->priv = &priv->fds;
}
else
{
ret = -EBUSY;
}
SPIS_CTRLR_QPOLL(priv->ctrlr);
if (priv->rx_length > 0)
{
eventset |= POLLOUT;
}
if (!SPIS_CTRLR_QFULL(priv->ctrlr))
{
eventset |= POLLIN;
}
poll_notify(&priv->fds, 1, eventset);
}
else if (fds->priv != NULL)
{
priv->fds = NULL;
fds->priv = NULL;
}
nxmutex_unlock(&priv->lock);
return ret;
}
/****************************************************************************
* Name: spi_slave_unlink
*
@ -552,6 +655,46 @@ static size_t spi_slave_receive(FAR struct spi_slave_dev_s *dev,
return BYTES2WORDS(recv_bytes);
}
/****************************************************************************
* Name: spi_slave_notify
*
* Description:
* This is a SPI device callback that is used when the SPI controller
* receives and sends complete or fail to notify spi slave upper half.
* And this callback can call in interrupt handler.
*
* Input Parameters:
* dev - SPI Slave device interface instance
* state - The Receive and send state, type of state is spi_slave_state_t
*
****************************************************************************/
static void spi_slave_notify(FAR struct spi_slave_dev_s *dev,
spi_slave_state_t state)
{
FAR struct spi_slave_driver_s *priv = (FAR struct spi_slave_driver_s *)dev;
if (state == SPISLAVE_TX_COMPLETE)
{
poll_notify(&priv->fds, 1, POLLIN);
}
else if (state == SPISLAVE_RX_COMPLETE)
{
int semcnt;
poll_notify(&priv->fds, 1, POLLOUT);
nxsem_get_value(&priv->wait, &semcnt);
if (semcnt < 1)
{
nxsem_post(&priv->wait);
}
}
else
{
spiinfo("sdev: %p transfer failed\n", dev);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -630,5 +773,3 @@ int spi_slave_register(FAR struct spi_slave_ctrlr_s *ctrlr, int bus)
return ret;
}
#endif /* CONFIG_SPI_SLAVE_DRIVER */

View file

@ -293,6 +293,22 @@
#define SPIS_DEV_RECEIVE(d,v,l) ((d)->ops->receive(d,v,l))
/****************************************************************************
* Name: SPIS_DEV_NOTIFY
*
* Description:
* This is a SPI device callback that is used when the SPI controller
* receives and sends complete or fail to notify spi slave upper half.
* And this callback can call in interrupt handler.
*
* Input Parameters:
* dev - SPI Slave device interface instance
* state - The Receive and send state, type of state is spi_slave_state_t
*
****************************************************************************/
#define SPIS_DEV_NOTIFY(d,s) ((d)->ops->notify(d,s))
/****************************************************************************
* Public Types
****************************************************************************/
@ -475,6 +491,15 @@ enum spi_slave_mode_e
SPISLAVE_MODE3 /* CPOL=1 CPHA=1 */
};
/* The SPI slave transfer state */
typedef enum
{
SPISLAVE_RX_COMPLETE = 0,
SPISLAVE_TX_COMPLETE,
SPISLAVE_TRANSFER_FAILED
} spi_slave_state_t;
/* The SPI slave controller driver vtable */
struct spi_slave_ctrlr_s; /* Forward reference */
@ -516,6 +541,8 @@ struct spi_slave_devops_s
FAR const void **data);
CODE size_t (*receive)(FAR struct spi_slave_dev_s *sdev,
FAR const void *data, size_t nwords);
CODE void (*notify)(FAR struct spi_slave_dev_s *sdev,
spi_slave_state_t state);
};
/* SPI slave device private data. This structure only defines the initial