1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  *   list of conditions and the following disclaimer in the documentation and/or
13  *   other materials provided with the distribution.
14  *
15  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16  *   contributors may be used to endorse or promote products derived from this
17  *   software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "ecspi.h"
32 
33 /*******************************************************************************
34  * Code
35  ******************************************************************************/
36 
37 /*******************************************************************************
38  * eCSPI Initialization and Configuration functions
39  ******************************************************************************/
40 /*FUNCTION**********************************************************************
41  *
42  * Function Name : ECSPI_Init
43  * Description   : Initializes the eCSPI module according to the specified
44  *                 parameters in the initConfig.
45  *
46  *END**************************************************************************/
ECSPI_Init(ECSPI_Type * base,const ecspi_init_config_t * initConfig)47 void ECSPI_Init(ECSPI_Type* base, const ecspi_init_config_t* initConfig)
48 {
49     /* Disable eCSPI module */
50     ECSPI_CONREG_REG(base) = 0;
51 
52     /* Enable the eCSPI module before write to other registers */
53     ECSPI_Enable(base);
54 
55     /* eCSPI CONREG Configuration */
56     ECSPI_CONREG_REG(base) |= ECSPI_CONREG_BURST_LENGTH(initConfig->burstLength) |
57                               ECSPI_CONREG_CHANNEL_SELECT(initConfig->channelSelect);
58     ECSPI_CONREG_REG(base) |= initConfig->ecspiAutoStart ? ECSPI_CONREG_SMC_MASK : 0;
59 
60     /* eCSPI CONFIGREG Configuration */
61     ECSPI_CONFIGREG_REG(base) = ECSPI_CONFIGREG_SCLK_PHA(((initConfig->clockPhase) & 1) << (initConfig->channelSelect)) |
62                                 ECSPI_CONFIGREG_SCLK_POL(((initConfig->clockPolarity) & 1) << (initConfig->channelSelect));
63 
64     /* Master or Slave mode Configuration */
65     if(initConfig->mode == ecspiMasterMode)
66     {
67         /* Set baud rate in bits per second */
68         ECSPI_CONREG_REG(base) |= ECSPI_CONREG_CHANNEL_MODE(1 << (initConfig->channelSelect));
69         ECSPI_SetBaudRate(base, initConfig->clockRate, initConfig->baudRate);
70     }
71     else
72         ECSPI_CONREG_REG(base) &= ~ECSPI_CONREG_CHANNEL_MODE(1 << (initConfig->channelSelect));
73 }
74 
75 /*FUNCTION**********************************************************************
76  *
77  * Function Name : ECSPI_SetSampClockSource
78  * Description   : Configure the clock source for the sample period counter.
79  *
80  *END**************************************************************************/
ECSPI_SetSampClockSource(ECSPI_Type * base,uint32_t source)81 void ECSPI_SetSampClockSource(ECSPI_Type* base, uint32_t source)
82 {
83     /* Select the clock source */
84     if(source == ecspiSclk)
85         ECSPI_PERIODREG_REG(base) &= ~ECSPI_PERIODREG_CSRC_MASK;
86     else
87         ECSPI_PERIODREG_REG(base) |= ECSPI_PERIODREG_CSRC_MASK;
88 }
89 
90 /*FUNCTION**********************************************************************
91  *
92  * Function Name : ECSPI_SetBaudRate
93  * Description   : Calculated the eCSPI baud rate in bits per second.
94  *
95  *END**************************************************************************/
ECSPI_SetBaudRate(ECSPI_Type * base,uint32_t sourceClockInHz,uint32_t bitsPerSec)96 uint32_t ECSPI_SetBaudRate(ECSPI_Type* base, uint32_t sourceClockInHz, uint32_t bitsPerSec)
97 {
98     uint32_t div, pre_div;
99     uint32_t post_baud;         /* baud rate after post divider */
100     uint32_t pre_baud;          /* baud rate before pre divider */
101 
102     if(sourceClockInHz <= bitsPerSec)
103     {
104         ECSPI_CONREG_REG(base) &= ~ECSPI_CONREG_PRE_DIVIDER_MASK;
105         ECSPI_CONREG_REG(base) &= ~ECSPI_CONREG_POST_DIVIDER_MASK;
106         return sourceClockInHz;
107     }
108 
109     div = sourceClockInHz / bitsPerSec;
110     if(div < 16)    /* pre_divider is enough */
111     {
112         if((sourceClockInHz - bitsPerSec * div) < ((bitsPerSec * (div + 1)) - sourceClockInHz))
113             pre_div = div - 1;   /* pre_divider value is one less than the real divider */
114         else
115             pre_div = div;
116         ECSPI_CONREG_REG(base) = (ECSPI_CONREG_REG(base) & (~ECSPI_CONREG_PRE_DIVIDER_MASK)) |
117                                  ECSPI_CONREG_PRE_DIVIDER(pre_div);
118         ECSPI_CONREG_REG(base) = (ECSPI_CONREG_REG(base) & (~ECSPI_CONREG_POST_DIVIDER_MASK)) |
119                                  ECSPI_CONREG_POST_DIVIDER(0);
120         return sourceClockInHz / (pre_div + 1);
121     }
122 
123     pre_baud = bitsPerSec * 16;
124     for(div = 1; div < 16; div++)
125     {
126         post_baud = sourceClockInHz >> div;
127         if(post_baud < pre_baud)
128         break;
129     }
130 
131     if(div == 16)     /* divider is not enough, set the biggest ones */
132     {
133         ECSPI_CONREG_REG(base) |= ECSPI_CONREG_PRE_DIVIDER(15);
134         ECSPI_CONREG_REG(base) |= ECSPI_CONREG_POST_DIVIDER(15);
135         return post_baud / 16;
136     }
137 
138     /* find the closed one */
139     if((post_baud - bitsPerSec * (post_baud / bitsPerSec)) < ((bitsPerSec * ((post_baud / bitsPerSec) + 1)) - post_baud))
140         pre_div = post_baud / bitsPerSec - 1;
141     else
142         pre_div = post_baud / bitsPerSec;
143     ECSPI_CONREG_REG(base) = (ECSPI_CONREG_REG(base) & (~ECSPI_CONREG_PRE_DIVIDER_MASK)) |
144                              ECSPI_CONREG_PRE_DIVIDER(pre_div);
145     ECSPI_CONREG_REG(base) = (ECSPI_CONREG_REG(base) & (~ECSPI_CONREG_POST_DIVIDER_MASK)) |
146                              ECSPI_CONREG_POST_DIVIDER(div);
147     return post_baud / (pre_div + 1);
148 }
149 
150 /*******************************************************************************
151  * DMA management functions
152  ******************************************************************************/
153 /*FUNCTION**********************************************************************
154  *
155  * Function Name : ECSPI_SetDMACmd
156  * Description   : Enable or disable the specified DMA Source.
157  *
158  *END**************************************************************************/
ECSPI_SetDMACmd(ECSPI_Type * base,uint32_t source,bool enable)159 void ECSPI_SetDMACmd(ECSPI_Type* base, uint32_t source, bool enable)
160 {
161     /* Configure the DAM source */
162     if(enable)
163         ECSPI_DMAREG_REG(base) |= ((uint32_t)(1 << source));
164     else
165         ECSPI_DMAREG_REG(base) &= ~((uint32_t)(1 << source));
166 }
167 
168 /*FUNCTION**********************************************************************
169  *
170  * Function Name : ECSPI_SetFIFOThreshold
171  * Description   : Set the RXFIFO or TXFIFO threshold.
172  *
173  *END**************************************************************************/
ECSPI_SetFIFOThreshold(ECSPI_Type * base,uint32_t fifo,uint32_t threshold)174 void ECSPI_SetFIFOThreshold(ECSPI_Type* base, uint32_t fifo, uint32_t threshold)
175 {
176     /* configure the RXFIFO and TXFIFO threshold that can triggers a DMA/INT request */
177     if(fifo == ecspiTxfifoThreshold)
178         ECSPI_DMAREG_REG(base) = (ECSPI_DMAREG_REG(base) & (~ECSPI_DMAREG_TX_THRESHOLD_MASK)) |
179                                  ECSPI_DMAREG_TX_THRESHOLD(threshold);
180     else
181         ECSPI_DMAREG_REG(base) = (ECSPI_DMAREG_REG(base) & (~ECSPI_DMAREG_RX_THRESHOLD_MASK)) |
182                                  ECSPI_DMAREG_RX_THRESHOLD(threshold);
183 }
184 
185 /*******************************************************************************
186  * Interrupts and flags management functions
187  ******************************************************************************/
188 /*FUNCTION**********************************************************************
189  *
190  * Function Name : ECSPI_SetIntCmd
191  * Description   : Enable or disable eCSPI interrupts.
192  *
193  *END**************************************************************************/
ECSPI_SetIntCmd(ECSPI_Type * base,uint32_t flags,bool enable)194 void ECSPI_SetIntCmd(ECSPI_Type* base, uint32_t flags, bool enable)
195 {
196     /* Configure the Interrupt source */
197     if(enable)
198         ECSPI_INTREG_REG(base) |= flags;
199     else
200         ECSPI_INTREG_REG(base) &= ~flags;
201 }
202 
203 /*******************************************************************************
204  * EOF
205  ******************************************************************************/
206