forked from apache/nuttx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspi_transfer.c
143 lines (113 loc) · 4.12 KB
/
spi_transfer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/****************************************************************************
* drivers/spi/spi_transfer.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/signal.h>
#include <nuttx/spi/spi.h>
#include <nuttx/spi/spi_transfer.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: spi_transfer
*
* Description:
* This is a helper function that can be used to encapsulate and manage
* a sequence of SPI transfers. The SPI bus will be locked and the
* SPI device selected for the duration of the transfers.
*
* Input Parameters:
* spi - An instance of the SPI device to use for the transfer
* seq - Describes the sequence of transfers.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int spi_transfer(FAR struct spi_dev_s *spi, FAR struct spi_sequence_s *seq)
{
FAR struct spi_trans_s *trans;
int ret = OK;
int i;
DEBUGASSERT(spi != NULL && seq != NULL && seq->trans != NULL);
/* Get exclusive access to the SPI bus */
SPI_LOCK(spi, true);
/* Establish the fixed SPI attributes for all transfers in the sequence */
SPI_SETFREQUENCY(spi, seq->frequency);
#ifdef CONFIG_SPI_DELAY_CONTROL
ret = SPI_SETDELAY(spi, seq->a, seq->b, seq->c, seq->i);
if (ret < 0)
{
spierr("ERROR: SPI_SETDELAY failed: %d\n", ret);
SPI_LOCK(spi, false);
return ret;
}
#endif
SPI_SETMODE(spi, (enum spi_mode_e)seq->mode);
SPI_SETBITS(spi, seq->nbits);
/* Select the SPI device in preparation for the transfer.
* REVISIT: This is redundant.
*/
SPI_SELECT(spi, seq->dev, true);
/* Then perform each transfer is the sequence */
for (i = 0, trans = seq->trans; i < (int)seq->ntrans; i++, trans++)
{
/* Establish the fixed SPI attributes for unique to this transaction */
#ifdef CONFIG_SPI_HWFEATURES
ret = SPI_HWFEATURES(spi, trans->hwfeat);
if (ret < 0)
{
spierr("ERROR: SPI_HWFEATURES failed: %d\n", ret);
break;
}
#endif
#ifdef CONFIG_SPI_CMDDATA
ret = SPI_CMDDATA(spi, seq->dev, trans->cmd);
if (ret < 0)
{
spierr("ERROR: SPI_CMDDATA failed: %d\n", ret);
break;
}
#endif
/* [Re-]select the SPI device in preparation for the transfer */
SPI_SELECT(spi, seq->dev, true);
/* Perform the transfer */
SPI_EXCHANGE(spi, trans->txbuffer, trans->rxbuffer, trans->nwords);
/* Possibly de-select the SPI device after the transfer */
if (trans->deselect)
{
SPI_SELECT(spi, seq->dev, false);
}
/* Perform any requested inter-transfer delay */
if (trans->delay > 0)
{
nxsig_usleep(trans->delay);
}
}
SPI_SELECT(spi, seq->dev, false);
SPI_LOCK(spi, false);
return ret;
}