Skip to content

Commit 5c7608c

Browse files
bradbrad
authored andcommitted
Add another convenience wrapper function to the SPI framework.
spi_sendv(spi_handle_t sh, const struct iovec *iov, int iovcnt) Takes a iovec of buffers and sends them as one transaction down the SPI bus. There exists devices that will not handle sending the register that is to be written to as one transaction and the data as a second transaction. That is, use one spi_send() to send the register and a second spi_send() to send the data. Those devices require a single transaction with both parts in it.
1 parent 29966ce commit 5c7608c

3 files changed

Lines changed: 60 additions & 5 deletions

File tree

share/man/man9/spi.9

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.\" $NetBSD: spi.9,v 1.2 2019/02/23 17:37:10 wiz Exp $
1+
.\" $NetBSD: spi.9,v 1.3 2025/10/10 18:36:17 brad Exp $
22
.\"
33
.\" Copyright (c) 2019 The NetBSD Foundation
44
.\" All rights reserved.
@@ -38,6 +38,7 @@
3838
.Nm spi_wait ,
3939
.Nm spi_done ,
4040
.Nm spi_send ,
41+
.Nm spi_sendv ,
4142
.Nm spi_recv ,
4243
.Nm spi_send_recv
4344
.Nd Serial Peripheral Interface (SPI) kernel interface
@@ -92,12 +93,18 @@
9293
.Fa "const uint8_t *data"
9394
.Fc
9495
.Ft int
96+
.Fo spi_sendv
97+
.Fa "struct spi_handle *sh"
98+
.Fa "struct iovec *iov"
99+
.Fa "int iovcnt"
100+
.Fc
101+
.Ft int
95102
.Fo spi_send_recv
96103
.Fa "struct spi_handle *sh"
97104
.Fa "int scnt"
98105
.Fa "const uint8_t *snd"
99106
.Fa "int rcnt"
100-
.Fa "const uint8_t *rcv"
107+
.Fa "uint8_t *rcv"
101108
.Fc
102109
.Sh DESCRIPTION
103110
SPI is a 4-wire synchronous full-duplex serial bus.
@@ -148,6 +155,8 @@ waits for it to complete.
148155
.It Fn spi_send "sh" "cnt" "data"
149156
Prepares a chunk for sending data, queues a transfer and
150157
waits for it to complete.
158+
.It Fn spi_sendv "sh" "iov" "iovcnt"
159+
Prepare and queue a scatter of chunks and wait for them to complete.
151160
.It Fn spi_send_recv "sh" "scnt" "snd" "rcnt" "rcv"
152161
Prepares two chunks for sending data first and then receiving
153162
an answer, queues a transfer and waits for it to complete.

sys/dev/spi/spi.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: spi.c,v 1.37 2025/09/21 13:02:08 thorpej Exp $ */
1+
/* $NetBSD: spi.c,v 1.38 2025/10/10 18:36:17 brad Exp $ */
22

33
/*-
44
* Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -44,18 +44,20 @@
4444
#include "opt_fdt.h" /* XXX */
4545

4646
#include <sys/cdefs.h>
47-
__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.37 2025/09/21 13:02:08 thorpej Exp $");
47+
__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.38 2025/10/10 18:36:17 brad Exp $");
4848

4949
#include "locators.h"
5050

5151
#include <sys/param.h>
5252
#include <sys/systm.h>
5353
#include <sys/device.h>
54+
#include <sys/kmem.h>
5455
#include <sys/conf.h>
5556
#include <sys/malloc.h>
5657
#include <sys/mutex.h>
5758
#include <sys/condvar.h>
5859
#include <sys/errno.h>
60+
#include <sys/uio.h>
5961

6062
#include <dev/spi/spivar.h>
6163
#include <dev/spi/spi_io.h>
@@ -686,6 +688,8 @@ spi_done(struct spi_transfer *st, int err)
686688
* done synchronously, i.e. send a command and get the response. This is
687689
* not full duplex. If you want full duplex, you can't use these convenience
688690
* wrappers.
691+
*
692+
* spi_sendv - scatter send data to the bus
689693
*/
690694
int
691695
spi_recv(spi_handle_t sh, int cnt, uint8_t *data)
@@ -749,3 +753,38 @@ spi_send_recv(spi_handle_t sh, int scnt, const uint8_t *snd,
749753

750754
return 0;
751755
}
756+
757+
int
758+
spi_sendv(spi_handle_t sh, const struct iovec *iov,
759+
int iovcnt)
760+
{
761+
struct spi_transfer trans;
762+
SIMPLEQ_HEAD(,spi_chunk_q) ck_q;
763+
struct spi_chunk_q *ce;
764+
765+
SIMPLEQ_INIT(&ck_q);
766+
767+
spi_transfer_init(&trans);
768+
for(int c = 0; c < iovcnt;c++) {
769+
ce = kmem_alloc(sizeof(struct spi_chunk_q),KM_NOSLEEP);
770+
if (ce == NULL)
771+
return ENOMEM;
772+
spi_chunk_init(&ce->chunk, iov[c].iov_len, iov[c].iov_base, NULL);
773+
spi_transfer_add(&trans, &ce->chunk);
774+
SIMPLEQ_INSERT_HEAD(&ck_q, ce, chunk_q);
775+
}
776+
777+
/* enqueue it and wait for it to complete */
778+
spi_transfer(sh, &trans);
779+
spi_wait(&trans);
780+
781+
while ((ce = SIMPLEQ_FIRST(&ck_q)) != NULL) {
782+
SIMPLEQ_REMOVE_HEAD(&ck_q, chunk_q);
783+
kmem_free(ce, sizeof(struct spi_chunk_q));
784+
}
785+
786+
if (trans.st_flags & SPI_F_ERROR)
787+
return trans.st_errno;
788+
789+
return 0;
790+
}

sys/dev/spi/spivar.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: spivar.h,v 1.25 2025/09/14 16:00:04 thorpej Exp $ */
1+
/* $NetBSD: spivar.h,v 1.26 2025/10/10 18:36:17 brad Exp $ */
22

33
/*-
44
* Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -46,6 +46,7 @@
4646

4747
#include <sys/device.h>
4848
#include <sys/queue.h>
49+
#include <sys/uio.h> /* for iovec */
4950

5051
/*
5152
* Serial Peripheral Interface bus. This is a 4-wire bus common for
@@ -192,8 +193,14 @@ void spi_wait(struct spi_transfer *);
192193
void spi_done(struct spi_transfer *, int);
193194

194195
/* convenience wrappers */
196+
struct spi_chunk_q {
197+
struct spi_chunk chunk;
198+
SIMPLEQ_ENTRY(spi_chunk_q) chunk_q;
199+
};
200+
195201
int spi_send(spi_handle_t, int, const uint8_t *);
196202
int spi_recv(spi_handle_t, int, uint8_t *);
197203
int spi_send_recv(spi_handle_t, int, const uint8_t *, int, uint8_t *);
204+
int spi_sendv(spi_handle_t, const struct iovec *, int);
198205

199206
#endif /* _DEV_SPI_SPIVAR_H_ */

0 commit comments

Comments
 (0)