@@ -128,7 +128,7 @@ static void spi_sam0_shift_master(SercomSpi *regs, struct spi_sam0_data *data)
128
128
u8_t tx ;
129
129
u8_t rx ;
130
130
131
- if (spi_context_tx_on (& data -> ctx )) {
131
+ if (spi_context_tx_buf_on (& data -> ctx )) {
132
132
tx = * (u8_t * )(data -> ctx .tx_buf );
133
133
} else {
134
134
tx = 0 ;
@@ -145,10 +145,10 @@ static void spi_sam0_shift_master(SercomSpi *regs, struct spi_sam0_data *data)
145
145
146
146
rx = regs -> DATA .reg ;
147
147
148
- if (spi_context_rx_on (& data -> ctx )) {
148
+ if (spi_context_rx_buf_on (& data -> ctx )) {
149
149
* data -> ctx .rx_buf = rx ;
150
- spi_context_update_rx (& data -> ctx , 1 , 1 );
151
150
}
151
+ spi_context_update_rx (& data -> ctx , 1 , 1 );
152
152
}
153
153
154
154
/* Fast path that transmits a buf */
@@ -173,103 +173,109 @@ static void spi_sam0_fast_tx(SercomSpi *regs, const struct spi_buf *tx_buf)
173
173
/* Fast path that reads into a buf */
174
174
static void spi_sam0_fast_rx (SercomSpi * regs , struct spi_buf * rx_buf )
175
175
{
176
- u8_t * p = rx_buf -> buf ;
177
- size_t len = rx_buf -> len ;
178
-
179
- while (regs -> INTFLAG .bit .RXC ) {
180
- (void )regs -> DATA .reg ;
181
- }
176
+ u8_t * rx = rx_buf -> buf ;
177
+ int len = rx_buf -> len ;
182
178
183
179
if (len <= 0 ) {
184
180
return ;
185
181
}
186
182
187
- /*
188
- * The code below interleaves the transmit of the next byte
189
- * with the receive of the next. The code is equivalent to:
190
- *
191
- * Transmit byte 0
192
- * Loop:
193
- * - Transmit byte n+1
194
- * - Receive byte n
195
- */
183
+ /* See the comment in spi_sam0_fast_txrx re: interleaving. */
196
184
197
- /* Load the first outgoing byte */
185
+ /* Ensure transmit is idle */
198
186
while (!regs -> INTFLAG .bit .DRE ) {
199
187
}
200
188
189
+ /* Flush the receive buffer */
190
+ while (regs -> INTFLAG .bit .RXC ) {
191
+ (void )regs -> DATA .reg ;
192
+ }
193
+
194
+ /* Write the first byte */
201
195
regs -> DATA .reg = 0 ;
196
+ len -- ;
202
197
203
198
while (len ) {
204
- if (len != 0 ) {
205
- while (!regs -> INTFLAG .bit .DRE ) {
206
- }
207
-
208
- regs -> DATA .reg = 0 ;
209
- }
210
-
211
- /*
212
- * Decrement len while waiting for the transfer to
213
- * complete.
214
- */
199
+ /* Load byte N+1 into the transmit register */
200
+ regs -> DATA .reg = 0 ;
215
201
len -- ;
216
202
203
+ /* Read byte N+0 from the receive register */
217
204
while (!regs -> INTFLAG .bit .RXC ) {
218
205
}
219
206
220
- * p ++ = regs -> DATA .reg ;
207
+ * rx ++ = regs -> DATA .reg ;
221
208
}
222
209
223
- /* Note that all transmits are complete and the RX buf is empty */
210
+ /* Read the final incoming byte */
211
+ while (!regs -> INTFLAG .bit .RXC ) {
212
+ }
213
+
214
+ * rx = regs -> DATA .reg ;
224
215
}
225
216
226
217
/* Fast path that writes and reads bufs of the same length */
227
218
static void spi_sam0_fast_txrx (SercomSpi * regs , const struct spi_buf * tx_buf ,
228
219
struct spi_buf * rx_buf )
229
220
{
230
- const u8_t * psrc = tx_buf -> buf ;
231
- u8_t * p = rx_buf -> buf ;
221
+ const u8_t * tx = tx_buf -> buf ;
222
+ const u8_t * txend = tx_buf -> buf + tx_buf -> len ;
223
+ u8_t * rx = rx_buf -> buf ;
232
224
size_t len = rx_buf -> len ;
233
225
234
- while (regs -> INTFLAG .bit .RXC ) {
235
- (void )regs -> DATA .reg ;
236
- }
237
-
238
226
if (len <= 0 ) {
239
227
return ;
240
228
}
241
229
242
- /* See the comment in spi_sam0_fast_rx re: interleaving. */
230
+ /*
231
+ * The code below interleaves the transmit writes with the
232
+ * receive reads to keep the bus fully utilised. The code is
233
+ * equivalent to:
234
+ *
235
+ * Transmit byte 0
236
+ * Loop:
237
+ * - Transmit byte n+1
238
+ * - Receive byte n
239
+ * Receive the final byte
240
+ */
243
241
244
- /* Load the first outgoing byte */
242
+ /* Ensure transmit is idle */
245
243
while (!regs -> INTFLAG .bit .DRE ) {
246
244
}
247
245
248
- regs -> DATA .reg = * psrc ++ ;
249
-
250
- while (len ) {
251
- if (len != 0 ) {
252
- while (!regs -> INTFLAG .bit .DRE ) {
253
- }
246
+ /* Flush the receive buffer */
247
+ while (regs -> INTFLAG .bit .RXC ) {
248
+ (void )regs -> DATA .reg ;
249
+ }
254
250
255
- regs -> DATA . reg = * psrc ++ ;
256
- }
251
+ /* Write the first byte */
252
+ regs -> DATA . reg = * tx ++ ;
257
253
258
- len -- ;
254
+ while (tx != txend ) {
255
+ /* Load byte N+1 into the transmit register. TX is
256
+ * single buffered and we have at most one byte in
257
+ * flight so skip the DRE check.
258
+ */
259
+ regs -> DATA .reg = * tx ++ ;
259
260
261
+ /* Read byte N+0 from the receive register */
260
262
while (!regs -> INTFLAG .bit .RXC ) {
261
263
}
262
264
263
- * p ++ = regs -> DATA .reg ;
265
+ * rx ++ = regs -> DATA .reg ;
266
+ }
267
+
268
+ /* Read the final incoming byte */
269
+ while (!regs -> INTFLAG .bit .RXC ) {
264
270
}
265
271
266
- /* Note that all transmits are complete and the RX buf is empty */
272
+ * rx = regs -> DATA . reg ;
267
273
}
268
274
269
275
/* Finish any ongoing writes and drop any remaining read data */
270
276
static void spi_sam0_finish (SercomSpi * regs )
271
277
{
272
- while (!regs -> INTFLAG .bit .TXC ) {
278
+ while (!regs -> INTFLAG .bit .DRE ) {
273
279
}
274
280
275
281
while (regs -> INTFLAG .bit .RXC ) {
@@ -287,7 +293,13 @@ static void spi_sam0_fast_transceive(struct spi_config *config,
287
293
SercomSpi * regs = cfg -> regs ;
288
294
289
295
while (tx_count != 0 && rx_count != 0 ) {
290
- spi_sam0_fast_txrx (regs , tx_bufs , rx_bufs );
296
+ if (tx_bufs -> buf == NULL ) {
297
+ spi_sam0_fast_rx (regs , rx_bufs );
298
+ } else if (rx_bufs -> buf == NULL ) {
299
+ spi_sam0_fast_tx (regs , tx_bufs );
300
+ } else {
301
+ spi_sam0_fast_txrx (regs , tx_bufs , rx_bufs );
302
+ }
291
303
tx_bufs ++ ;
292
304
tx_count -- ;
293
305
rx_bufs ++ ;
@@ -350,10 +362,10 @@ static int spi_sam0_transceive(struct spi_config *config,
350
362
spi_context_cs_configure (& data -> ctx );
351
363
spi_context_cs_control (& data -> ctx , true);
352
364
353
- /* This driver special case for the common send only, receive
365
+ /* This driver special cases the common send only, receive
354
366
* only, and transmit then receive operations. This special
355
367
* casing is 4x faster than the spi_context() routines
356
- * and also allows the transmit and receive to be interleaved.
368
+ * and allows the transmit and receive to be interleaved.
357
369
*/
358
370
if (spi_sam0_is_regular (tx_bufs , tx_count , rx_bufs , rx_count )) {
359
371
spi_sam0_fast_transceive (config , tx_bufs , tx_count , rx_bufs ,
@@ -374,6 +386,17 @@ static int spi_sam0_transceive(struct spi_config *config,
374
386
return err ;
375
387
}
376
388
389
+ #ifdef CONFIG_POLL
390
+ static int spi_sam0_transceive_async (struct spi_config * config ,
391
+ const struct spi_buf * tx_bufs ,
392
+ size_t tx_count , struct spi_buf * rx_bufs ,
393
+ size_t rx_count ,
394
+ struct k_poll_signal * async )
395
+ {
396
+ return - ENOTSUP ;
397
+ }
398
+ #endif
399
+
377
400
static int spi_sam0_release (struct spi_config * config )
378
401
{
379
402
struct spi_sam0_data * data = config -> dev -> driver_data ;
@@ -416,6 +439,9 @@ static int spi_sam0_init(struct device *dev)
416
439
417
440
static const struct spi_driver_api spi_sam0_driver_api = {
418
441
.transceive = spi_sam0_transceive ,
442
+ #ifdef CONFIG_POLL
443
+ .transceive_async = spi_sam0_transceive_async ,
444
+ #endif
419
445
.release = spi_sam0_release ,
420
446
};
421
447
0 commit comments