1 /******************************************************************************
2 *  Filename:       ssi.c
3 *  Revised:        2015-11-16 19:41:47 +0100 (Mon, 16 Nov 2015)
4 *  Revision:       45094
5 *
6 *  Description:    Driver for Synchronous Serial Interface
7 *
8 *  Copyright (c) 2015, Texas Instruments Incorporated
9 *  All rights reserved.
10 *
11 *  Redistribution and use in source and binary forms, with or without
12 *  modification, are permitted provided that the following conditions are met:
13 *
14 *  1) Redistributions of source code must retain the above copyright notice,
15 *     this list of conditions and the following disclaimer.
16 *
17 *  2) Redistributions in binary form must reproduce the above copyright notice,
18 *     this list of conditions and the following disclaimer in the documentation
19 *     and/or other materials provided with the distribution.
20 *
21 *  3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 *     be used to endorse or promote products derived from this software without
23 *     specific prior written permission.
24 *
25 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 *  POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38 
39 #include <driverlib/ssi.h>
40 
41 //*****************************************************************************
42 //
43 // Handle support for DriverLib in ROM:
44 // This section will undo prototype renaming made in the header file
45 //
46 //*****************************************************************************
47 #if !defined(DOXYGEN)
48     #undef  SSIConfigSetExpClk
49     #define SSIConfigSetExpClk              NOROM_SSIConfigSetExpClk
50     #undef  SSIDataPut
51     #define SSIDataPut                      NOROM_SSIDataPut
52     #undef  SSIDataPutNonBlocking
53     #define SSIDataPutNonBlocking           NOROM_SSIDataPutNonBlocking
54     #undef  SSIDataGet
55     #define SSIDataGet                      NOROM_SSIDataGet
56     #undef  SSIDataGetNonBlocking
57     #define SSIDataGetNonBlocking           NOROM_SSIDataGetNonBlocking
58     #undef  SSIIntRegister
59     #define SSIIntRegister                  NOROM_SSIIntRegister
60     #undef  SSIIntUnregister
61     #define SSIIntUnregister                NOROM_SSIIntUnregister
62 #endif
63 
64 //*****************************************************************************
65 //
66 //! Configures the synchronous serial port
67 //
68 //*****************************************************************************
69 void
SSIConfigSetExpClk(uint32_t ui32Base,uint32_t ui32SSIClk,uint32_t ui32Protocol,uint32_t ui32Mode,uint32_t ui32BitRate,uint32_t ui32DataWidth)70 SSIConfigSetExpClk(uint32_t ui32Base, uint32_t ui32SSIClk,
71                    uint32_t ui32Protocol, uint32_t ui32Mode,
72                    uint32_t ui32BitRate, uint32_t ui32DataWidth)
73 {
74     uint32_t ui32MaxBitRate;
75     uint32_t ui32RegVal;
76     uint32_t ui32PreDiv;
77     uint32_t ui32SCR;
78     uint32_t ui32SPH_SPO;
79 
80     //
81     // Check the arguments.
82     //
83     ASSERT(SSIBaseValid(ui32Base));
84     ASSERT((ui32Protocol == SSI_FRF_MOTO_MODE_0) ||
85            (ui32Protocol == SSI_FRF_MOTO_MODE_1) ||
86            (ui32Protocol == SSI_FRF_MOTO_MODE_2) ||
87            (ui32Protocol == SSI_FRF_MOTO_MODE_3) ||
88            (ui32Protocol == SSI_FRF_TI) ||
89            (ui32Protocol == SSI_FRF_NMW));
90     ASSERT((ui32Mode == SSI_MODE_MASTER) ||
91            (ui32Mode == SSI_MODE_SLAVE) ||
92            (ui32Mode == SSI_MODE_SLAVE_OD));
93     ASSERT(((ui32Mode == SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 2))) ||
94            ((ui32Mode != SSI_MODE_MASTER) && (ui32BitRate <= (ui32SSIClk / 12))));
95     ASSERT((ui32SSIClk / ui32BitRate) <= (254 * 256));
96     ASSERT((ui32DataWidth >= 4) && (ui32DataWidth <= 16));
97 
98     //
99     // Set the mode.
100     //
101     ui32RegVal = (ui32Mode == SSI_MODE_SLAVE_OD) ? SSI_CR1_SOD : 0;
102     ui32RegVal |= (ui32Mode == SSI_MODE_MASTER) ? 0 : SSI_CR1_MS;
103     HWREG(ui32Base + SSI_O_CR1) = ui32RegVal;
104 
105     //
106     // Set the clock predivider.
107     //
108     ui32MaxBitRate = ui32SSIClk / ui32BitRate;
109     ui32PreDiv = 0;
110     do
111     {
112         ui32PreDiv += 2;
113         ui32SCR = (ui32MaxBitRate / ui32PreDiv) - 1;
114     }
115     while(ui32SCR > 255);
116     HWREG(ui32Base + SSI_O_CPSR) = ui32PreDiv;
117 
118     //
119     // Set protocol and clock rate.
120     //
121     ui32SPH_SPO = (ui32Protocol & 3) << 6;
122     ui32Protocol &= SSI_CR0_FRF_M;
123     ui32RegVal = (ui32SCR << 8) | ui32SPH_SPO | ui32Protocol | (ui32DataWidth - 1);
124     HWREG(ui32Base + SSI_O_CR0) = ui32RegVal;
125 }
126 
127 //*****************************************************************************
128 //
129 //! Puts a data element into the SSI transmit FIFO
130 //
131 //*****************************************************************************
132 int32_t
SSIDataPutNonBlocking(uint32_t ui32Base,uint32_t ui32Data)133 SSIDataPutNonBlocking(uint32_t ui32Base, uint32_t ui32Data)
134 {
135     //
136     // Check the arguments.
137     //
138     ASSERT(SSIBaseValid(ui32Base));
139     ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
140                                        SSI_CR0_DSS_M))) == 0);
141 
142     //
143     // Check for space to write.
144     //
145     if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF)
146     {
147         HWREG(ui32Base + SSI_O_DR) = ui32Data;
148         return(1);
149     }
150     else
151     {
152         return(0);
153     }
154 }
155 
156 
157 //*****************************************************************************
158 //
159 //! Puts a data element into the SSI transmit FIFO
160 //
161 //*****************************************************************************
162 void
SSIDataPut(uint32_t ui32Base,uint32_t ui32Data)163 SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
164 {
165     //
166     // Check the arguments.
167     //
168     ASSERT(SSIBaseValid(ui32Base));
169     ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
170                                        SSI_CR0_DSS_M))) == 0);
171 
172     //
173     // Wait until there is space.
174     //
175     while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
176     {
177     }
178 
179     //
180     // Write the data to the SSI.
181     //
182     HWREG(ui32Base + SSI_O_DR) = ui32Data;
183 }
184 
185 //*****************************************************************************
186 //
187 //! Gets a data element from the SSI receive FIFO
188 //
189 //*****************************************************************************
190 void
SSIDataGet(uint32_t ui32Base,uint32_t * pui32Data)191 SSIDataGet(uint32_t ui32Base, uint32_t *pui32Data)
192 {
193     //
194     // Check the arguments.
195     //
196     ASSERT(SSIBaseValid(ui32Base));
197 
198     //
199     // Wait until there is data to be read.
200     //
201     while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE))
202     {
203     }
204 
205     //
206     // Read data from SSI.
207     //
208     *pui32Data = HWREG(ui32Base + SSI_O_DR);
209 }
210 
211 //*****************************************************************************
212 //
213 //! Gets a data element from the SSI receive FIFO
214 //!
215 //! \param ui32Base specifies the SSI module base address.
216 //! \param pui32Data is a pointer to a storage location for data that was
217 //! received over the SSI interface.
218 //!
219 //! This function gets received data from the receive FIFO of the specified SSI
220 //! module and places that data into the location specified by the \e ui32Data
221 //! parameter. If there is no data in the FIFO, then this function  returns a
222 //! zero.
223 //!
224 //! \note Only the lower N bits of the value written to \e pui32Data contain
225 //! valid data, where N is the data width as configured by \sa
226 //! SSIConfigSetExpClk(). For example, if the interface is configured for
227 //! 8-bit data width, only the lower 8 bits of the value written to \e pui32Data
228 //! contain valid data.
229 //!
230 //! \return Returns the number of elements read from the SSI receive FIFO.
231 //
232 //*****************************************************************************
233 int32_t
SSIDataGetNonBlocking(uint32_t ui32Base,uint32_t * pui32Data)234 SSIDataGetNonBlocking(uint32_t ui32Base, uint32_t *pui32Data)
235 {
236     //
237     // Check the arguments.
238     //
239     ASSERT(SSIBaseValid(ui32Base));
240 
241     //
242     // Check for data to read.
243     //
244     if(HWREG(ui32Base + SSI_O_SR) & SSI_SR_RNE)
245     {
246         *pui32Data = HWREG(ui32Base + SSI_O_DR);
247         return(1);
248     }
249     else
250     {
251         return(0);
252     }
253 }
254 
255 //*****************************************************************************
256 //
257 //! Registers an interrupt handler for the synchronous serial port
258 //!
259 //! \param ui32Base specifies the SSI module base address.
260 //! \param pfnHandler is a pointer to the function to be called when the
261 //! synchronous serial port interrupt occurs.
262 //!
263 //! This sets the handler to be called when an SSI interrupt
264 //! occurs. This will enable the global interrupt in the interrupt controller;
265 //! specific SSI interrupts must be enabled via SSIIntEnable(). If necessary,
266 //! it is the interrupt handler's responsibility to clear the interrupt source
267 //! via SSIIntClear().
268 //!
269 //! \sa IntRegister() for important information about registering interrupt
270 //! handlers.
271 //!
272 //! \return None
273 //
274 //*****************************************************************************
275 void
SSIIntRegister(uint32_t ui32Base,void (* pfnHandler)(void))276 SSIIntRegister(uint32_t ui32Base, void (*pfnHandler)(void))
277 {
278     uint32_t ui32Int;
279 
280     //
281     // Check the arguments.
282     //
283     ASSERT(SSIBaseValid(ui32Base));
284 
285     //
286     // Determine the interrupt number based on the SSI port.
287     //
288     ui32Int = (ui32Base == SSI0_BASE) ? INT_SSI0_COMB : INT_SSI1_COMB;
289 
290     //
291     // Register the interrupt handler.
292     //
293     IntRegister(ui32Int, pfnHandler);
294 
295     //
296     // Enable the synchronous serial port interrupt.
297     //
298     IntEnable(ui32Int);
299 }
300 
301 //*****************************************************************************
302 //
303 //! Unregisters an interrupt handler for the synchronous serial port
304 //!
305 //! \param ui32Base specifies the SSI module base address.
306 //!
307 //! This function will clear the handler to be called when a SSI
308 //! interrupt occurs. This will also mask off the interrupt in the interrupt
309 //! controller so that the interrupt handler no longer is called.
310 //!
311 //! \sa IntRegister() for important information about registering interrupt
312 //! handlers.
313 //!
314 //! \return None
315 //
316 //*****************************************************************************
317 void
SSIIntUnregister(uint32_t ui32Base)318 SSIIntUnregister(uint32_t ui32Base)
319 {
320     uint32_t ui32Int;
321 
322     //
323     // Check the arguments.
324     //
325     ASSERT(SSIBaseValid(ui32Base));
326 
327     //
328     // Determine the interrupt number based on the SSI port.
329     //
330     ui32Int = (ui32Base == SSI0_BASE) ? INT_SSI0_COMB : INT_SSI1_COMB;
331 
332     //
333     // Disable the interrupt.
334     //
335     IntDisable(ui32Int);
336 
337     //
338     // Unregister the interrupt handler.
339     //
340     IntUnregister(ui32Int);
341 }
342