1 /******************************************************************************
2 *  Filename:       ssi.c
3 *
4 *  Description:    Driver for Synchronous Serial Interface
5 *
6 *  Copyright (c) 2015 - 2022, Texas Instruments Incorporated
7 *  All rights reserved.
8 *
9 *  Redistribution and use in source and binary forms, with or without
10 *  modification, are permitted provided that the following conditions are met:
11 *
12 *  1) Redistributions of source code must retain the above copyright notice,
13 *     this list of conditions and the following disclaimer.
14 *
15 *  2) Redistributions in binary form must reproduce the above copyright notice,
16 *     this list of conditions and the following disclaimer in the documentation
17 *     and/or other materials provided with the distribution.
18 *
19 *  3) Neither the name of the ORGANIZATION nor the names of its contributors may
20 *     be used to endorse or promote products derived from this software without
21 *     specific prior written permission.
22 *
23 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 *  POSSIBILITY OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36 
37 #include "ssi.h"
38 
39 //*****************************************************************************
40 //
41 // Handle support for DriverLib in ROM:
42 // This section will undo prototype renaming made in the header file
43 //
44 //*****************************************************************************
45 #if !defined(DOXYGEN)
46     #undef  SSIConfigSetExpClk
47     #define SSIConfigSetExpClk              NOROM_SSIConfigSetExpClk
48     #undef  SSIDataPut
49     #define SSIDataPut                      NOROM_SSIDataPut
50     #undef  SSIDataPutNonBlocking
51     #define SSIDataPutNonBlocking           NOROM_SSIDataPutNonBlocking
52     #undef  SSIDataGet
53     #define SSIDataGet                      NOROM_SSIDataGet
54     #undef  SSIDataGetNonBlocking
55     #define SSIDataGetNonBlocking           NOROM_SSIDataGetNonBlocking
56     #undef  SSIIntRegister
57     #define SSIIntRegister                  NOROM_SSIIntRegister
58     #undef  SSIIntUnregister
59     #define SSIIntUnregister                NOROM_SSIIntUnregister
60 #endif
61 
62 //*****************************************************************************
63 //
64 // Configures the synchronous serial port
65 //
66 //*****************************************************************************
67 void
SSIConfigSetExpClk(uint32_t ui32Base,uint32_t ui32SSIClk,uint32_t ui32Protocol,uint32_t ui32Mode,uint32_t ui32BitRate,uint32_t ui32DataWidth)68 SSIConfigSetExpClk(uint32_t ui32Base, uint32_t ui32SSIClk,
69                    uint32_t ui32Protocol, uint32_t ui32Mode,
70                    uint32_t ui32BitRate, uint32_t ui32DataWidth)
71 {
72     uint32_t ui32MaxBitRate;
73     uint32_t ui32RegVal;
74     uint32_t ui32PreDiv;
75     uint32_t ui32SCR;
76     uint32_t ui32SPH_SPO;
77 
78     // Check the arguments.
79     ASSERT(SSIBaseValid(ui32Base));
80     ASSERT((ui32Protocol == SSI_FRF_MOTO_MODE_0) ||
81            (ui32Protocol == SSI_FRF_MOTO_MODE_1) ||
82            (ui32Protocol == SSI_FRF_MOTO_MODE_2) ||
83            (ui32Protocol == SSI_FRF_MOTO_MODE_3) ||
84            (ui32Protocol == SSI_FRF_TI) ||
85            (ui32Protocol == SSI_FRF_NMW));
86     ASSERT((ui32Mode == SSI_MODE_MASTER) ||
87            (ui32Mode == SSI_MODE_SLAVE) ||
88            (ui32Mode == SSI_MODE_SLAVE_OD));
89     ASSERT(((ui32Mode == SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 2))) ||
90            ((ui32Mode != SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 12))));
91     ASSERT((ui32SSIClk / ui32BitRate) <= (254 * 256));
92     ASSERT((ui32DataWidth >= 4) && (ui32DataWidth <= 16));
93 
94     // Set the mode.
95     ui32RegVal = (ui32Mode == SSI_MODE_SLAVE_OD) ? SSI_CR1_SOD : 0;
96     ui32RegVal |= (ui32Mode == SSI_MODE_MASTER) ? 0 : SSI_CR1_MS;
97     HWREG(ui32Base + SSI_O_CR1) = ui32RegVal;
98 
99     // Set the clock predivider.
100     ui32MaxBitRate = ui32SSIClk / ui32BitRate;
101     ui32PreDiv = 0;
102     do
103     {
104         ui32PreDiv += 2;
105         ui32SCR = (ui32MaxBitRate / ui32PreDiv) - 1;
106     }
107     while(ui32SCR > 255);
108     HWREG(ui32Base + SSI_O_CPSR) = ui32PreDiv;
109 
110     // Set protocol and clock rate.
111     ui32SPH_SPO = (ui32Protocol & 3) << 6;
112     ui32Protocol &= SSI_CR0_FRF_M;
113     ui32RegVal = (ui32SCR << 8) | ui32SPH_SPO | ui32Protocol | (ui32DataWidth - 1);
114     HWREG(ui32Base + SSI_O_CR0) = ui32RegVal;
115 }
116 
117 //*****************************************************************************
118 //
119 // Puts a data element into the SSI transmit FIFO
120 //
121 //*****************************************************************************
122 int32_t
SSIDataPutNonBlocking(uint32_t ui32Base,uint32_t ui32Data)123 SSIDataPutNonBlocking(uint32_t ui32Base, uint32_t ui32Data)
124 {
125     // Check the arguments.
126     ASSERT(SSIBaseValid(ui32Base));
127     ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
128                                        SSI_CR0_DSS_M))) == 0);
129 
130     // Check for space to write.
131     if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF)
132     {
133         HWREG(ui32Base + SSI_O_DR) = ui32Data;
134         return(1);
135     }
136     else
137     {
138         return(0);
139     }
140 }
141 
142 //*****************************************************************************
143 //
144 // Puts a data element into the SSI transmit FIFO
145 //
146 //*****************************************************************************
147 void
SSIDataPut(uint32_t ui32Base,uint32_t ui32Data)148 SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
149 {
150     // Check the arguments.
151     ASSERT(SSIBaseValid(ui32Base));
152     ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
153                                        SSI_CR0_DSS_M))) == 0);
154 
155     // Wait until there is space.
156     while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
157     {
158     }
159 
160     // Write the data to the SSI.
161     HWREG(ui32Base + SSI_O_DR) = ui32Data;
162 }
163 
164 //*****************************************************************************
165 //
166 // Gets a data element from the SSI receive FIFO
167 //
168 //*****************************************************************************
169 void
SSIDataGet(uint32_t ui32Base,uint32_t * pui32Data)170 SSIDataGet(uint32_t ui32Base, uint32_t *pui32Data)
171 {
172     // Check the arguments.
173     ASSERT(SSIBaseValid(ui32Base));
174 
175     // Wait until there is data to be read.
176     while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE))
177     {
178     }
179 
180     // Read data from SSI.
181     *pui32Data = HWREG(ui32Base + SSI_O_DR);
182 }
183 
184 //*****************************************************************************
185 //
186 // Gets a data element from the SSI receive FIFO
187 //
188 //*****************************************************************************
189 int32_t
SSIDataGetNonBlocking(uint32_t ui32Base,uint32_t * pui32Data)190 SSIDataGetNonBlocking(uint32_t ui32Base, uint32_t *pui32Data)
191 {
192     // Check the arguments.
193     ASSERT(SSIBaseValid(ui32Base));
194 
195     // Check for data to read.
196     if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE)
197     {
198         *pui32Data = HWREG(ui32Base + SSI_O_DR);
199         return(1);
200     }
201     else
202     {
203         return(0);
204     }
205 }
206 
207 //*****************************************************************************
208 //
209 // Registers an interrupt handler for the synchronous serial port
210 //
211 //*****************************************************************************
212 void
SSIIntRegister(uint32_t ui32Base,void (* pfnHandler)(void))213 SSIIntRegister(uint32_t ui32Base, void (*pfnHandler)(void))
214 {
215     uint32_t ui32Int;
216 
217     // Check the arguments.
218     ASSERT(SSIBaseValid(ui32Base));
219 
220     // Determine the interrupt number based on the SSI port.
221     ui32Int = (ui32Base == SSI0_BASE) ? INT_SSI0_COMB : INT_SSI1_COMB;
222 
223     // Register the interrupt handler.
224     IntRegister(ui32Int, pfnHandler);
225 
226     // Enable the synchronous serial port interrupt.
227     IntEnable(ui32Int);
228 }
229 
230 //*****************************************************************************
231 //
232 // Unregisters an interrupt handler for the synchronous serial port
233 //
234 //*****************************************************************************
235 void
SSIIntUnregister(uint32_t ui32Base)236 SSIIntUnregister(uint32_t ui32Base)
237 {
238     uint32_t ui32Int;
239 
240     // Check the arguments.
241     ASSERT(SSIBaseValid(ui32Base));
242 
243     // Determine the interrupt number based on the SSI port.
244     ui32Int = (ui32Base == SSI0_BASE) ? INT_SSI0_COMB : INT_SSI1_COMB;
245 
246     // Disable the interrupt.
247     IntDisable(ui32Int);
248 
249     // Unregister the interrupt handler.
250     IntUnregister(ui32Int);
251 }
252