1 
2 /**
3  * @file xmc_sdmmc.c
4  * @date 2019-05-07
5  *
6  * @cond
7  *********************************************************************************************************************
8  * XMClib v2.1.24 - XMC Peripheral Driver Library
9  *
10  * Copyright (c) 2015-2019, Infineon Technologies AG
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
14  * following conditions are met:
15  *
16  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
17  * disclaimer.
18  *
19  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
20  * disclaimer in the documentation and/or other materials provided with the distribution.
21  *
22  * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
23  * products derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
34  * Infineon Technologies AG dave@infineon.com).
35  *********************************************************************************************************************
36  *
37  * Change History
38  * --------------
39  *
40  * 2015-02-20:
41  *     - Initial <br>
42  *     - Removed GetDriverVersion API <br>
43  *
44  * 2015-06-20:
45  *     - Removed definition of GetDriverVersion API <br>
46  *
47  * 2016-03-14:
48  *     - Values are directly assigned to the int status registers <br>
49  *
50  * 2016-07-11:
51  *     - XMC_SDMMC_SetDataTransferMode() shall not invoke SetDateLineTimeout() <br>
52  *
53  * 2019-05-07:
54  *     - Fixed compilation warnings
55  *
56  * @endcond
57  */
58 
59 /**
60  * @addtogroup XMClib
61  * @{
62  */
63 
64 /**
65  * @addtogroup SDMMC
66  * @brief SDMMC driver
67  * @{
68  */
69 
70 /*******************************************************************************
71  * HEADER FILES
72  *******************************************************************************/
73 
74 #include "xmc_sdmmc.h"
75 
76 /*
77  * The SDMMC peripheral is only available on the
78  * XMC4500. The SDMMC definition can be found in
79  * the XMC4500.h (device header file).
80  */
81 #if defined (SDMMC)
82 #include "xmc_scu.h"
83 
84 /*******************************************************************************
85  * MACROS
86  *******************************************************************************/
87 
88 /*
89  * Check for valid SDMMC error events <br>
90  *
91  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
92  */
93 #define XMC_SDMMC_CHECK_ERROR_EVENT(e)\
94   ((e == XMC_SDMMC_CMD_TIMEOUT_ERR)     ||\
95    (e == XMC_SDMMC_CMD_CRC_ERR)         ||\
96    (e == XMC_SDMMC_CMD_END_BIT_ERR)     ||\
97    (e == XMC_SDMMC_CMD_IND_ERR)         ||\
98    (e == XMC_SDMMC_DATA_TIMEOUT_ERR)    ||\
99    (e == XMC_SDMMC_DATA_CRC_ERR)        ||\
100    (e == XMC_SDMMC_DATA_END_BIT_ERR)    ||\
101    (e == XMC_SDMMC_CURRENT_LIMIT_ERR)   ||\
102    (e == XMC_SDMMC_ACMD_ERR)            ||\
103    (e == XMC_SDMMC_TARGET_RESP_ERR))
104 
105 /*
106  * Check for valid SDMMC normal events <br>
107  *
108  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
109  */
110 #define XMC_SDMMC_CHECK_NORMAL_EVENT(e)\
111   ((e == XMC_SDMMC_CMD_COMPLETE)        ||\
112    (e == XMC_SDMMC_TX_COMPLETE)         ||\
113    (e == XMC_SDMMC_BLOCK_GAP_EVENT)     ||\
114    (e == XMC_SDMMC_BUFFER_WRITE_READY)  ||\
115    (e == XMC_SDMMC_BUFFER_READ_READY)   ||\
116    (e == XMC_SDMMC_CARD_INS)            ||\
117    (e == XMC_SDMMC_CARD_REMOVAL)        ||\
118    (e == XMC_SDMMC_CARD_INT))
119 
120 /*
121  * Check for both normal and error events <br>
122  *
123  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
124  */
125 #define XMC_SDMMC_CHECK_EVENT(e)\
126   ((XMC_SDMMC_CHECK_NORMAL_EVENT(e))    ||\
127    (XMC_SDMMC_CHECK_ERROR_EVENT(e)))
128 
129 /*
130  * Check for valid SDMMC wakeup events <br>
131  *
132  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
133  */
134 #define XMC_SDMMC_CHECK_WAKEUP_EVENT(w)\
135   ((w == XMC_SDMMC_WAKEUP_EN_CARD_INT)  ||\
136    (w == XMC_SDMMC_WAKEUP_EN_CARD_INS)  ||\
137    (w == XMC_SDMMC_WAKEUP_EN_CARD_REM))
138 
139 /*
140  * Check for valid SDMMC software reset modes <br>
141  *
142  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
143  */
144 #define XMC_SDMMC_CHECK_SW_RESET_MODE(m)\
145   ((m == XMC_SDMMC_SW_RESET_ALL)        ||\
146    (m == XMC_SDMMC_SW_RST_CMD_LINE)     ||\
147    (m == XMC_SDMMC_SW_RST_DAT_LINE))
148 
149 /*
150  * Check for valid SDMMC transfer modes <br>
151  *
152  * This macro is used in the LLD for assertion checks (XMC_ASSERT).
153  */
154 #define XMC_SDMMC_CHECK_TRANSFER_MODE(m)\
155   ((m == XMC_SDMMC_TRANSFER_MODE_TYPE_SINGLE)    ||\
156    (m == XMC_SDMMC_TRANSFER_MODE_TYPE_INFINITE)  ||\
157    (m == XMC_SDMMC_TRANSFER_MODE_TYPE_MULTIPLE)  ||\
158    (m == XMC_SDMMC_TRANSFER_MODE_TYPE_STOP_MULTIPLE))
159 
160 
161 /*******************************************************************************
162  * API IMPLEMENTATION
163  *******************************************************************************/
164 
165 /* Get power status of the SDMMC peripheral */
XMC_SDMMC_GetPowerStatus(XMC_SDMMC_t * const sdmmc)166 bool XMC_SDMMC_GetPowerStatus(XMC_SDMMC_t *const sdmmc)
167 {
168   XMC_ASSERT("XMC_SDMMC_GetPowerStatus: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
169 
170   return (bool)(sdmmc->POWER_CTRL & SDMMC_POWER_CTRL_SD_BUS_POWER_Msk);
171 }
172 
173 /*
174  * De-assert the peripheral reset. The SDMMC peripheral
175  * needs to be initialized
176  */
XMC_SDMMC_Enable(XMC_SDMMC_t * const sdmmc)177 void XMC_SDMMC_Enable(XMC_SDMMC_t *const sdmmc)
178 {
179   XMC_ASSERT("XMC_SDMMC_Enable: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
180   XMC_UNUSED_ARG(sdmmc);
181 
182 #if defined(CLOCK_GATING_SUPPORTED)
183   XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_SDMMC);
184 #endif
185 #if defined(PERIPHERAL_RESET_SUPPORTED)
186   XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_SDMMC);
187 #endif
188 }
189 
190 /* Assert the peripheral reset */
XMC_SDMMC_Disable(XMC_SDMMC_t * const sdmmc)191 void XMC_SDMMC_Disable(XMC_SDMMC_t *const sdmmc)
192 {
193   XMC_ASSERT("XMC_SDMMC_Disable: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
194   XMC_UNUSED_ARG(sdmmc);
195 
196 #if defined(PERIPHERAL_RESET_SUPPORTED)
197   XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_SDMMC);
198 #endif
199 #if defined(CLOCK_GATING_SUPPORTED)
200   XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_SDMMC);
201 #endif
202 }
203 
204 /* Initialize SDMMC peripheral */
XMC_SDMMC_Init(XMC_SDMMC_t * const sdmmc,const XMC_SDMMC_CONFIG_t * config)205 XMC_SDMMC_STATUS_t XMC_SDMMC_Init(XMC_SDMMC_t *const sdmmc, const XMC_SDMMC_CONFIG_t *config)
206 {
207   XMC_ASSERT("XMC_SDMMC_Init: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
208   XMC_ASSERT("XMC_SDMMC_Init: Invalid clock divider value", XMC_SDMMC_CHECK_SDCLK_FREQ(config->clock_divider));
209   XMC_ASSERT("XMC_SDMMC_Init: Invalid bus width", XMC_SDMMC_CHECK_DATA_LINES(config->bus_width));
210 
211   /* Enable SDMMC peripheral */
212   XMC_SDMMC_Enable(sdmmc);
213 
214   /* Write internal clock divider register */
215   sdmmc->CLOCK_CTRL |= (uint16_t)((uint32_t)config->clock_divider << SDMMC_CLOCK_CTRL_SDCLK_FREQ_SEL_Pos);
216 
217   /* Set bus width */
218   sdmmc->HOST_CTRL = (uint8_t)((sdmmc->HOST_CTRL & (uint8_t)~SDMMC_HOST_CTRL_DATA_TX_WIDTH_Msk) |
219                                ((uint8_t)config->bus_width << SDMMC_HOST_CTRL_DATA_TX_WIDTH_Pos));
220 
221   return XMC_SDMMC_STATUS_SUCCESS;
222 }
223 
224 /* Enable event status */
XMC_SDMMC_EnableEventStatus(XMC_SDMMC_t * const sdmmc,uint32_t event)225 void XMC_SDMMC_EnableEventStatus(XMC_SDMMC_t *const sdmmc, uint32_t event)
226 {
227   XMC_ASSERT("XMC_SDMMC_EnableEventStatus: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
228 
229   /* Set INT status enable register */
230   sdmmc->EN_INT_STATUS_NORM |= (uint16_t)event;
231   sdmmc->EN_INT_STATUS_ERR |= (uint16_t)(event >> 16U);
232 }
233 
234 /* Disable event status */
XMC_SDMMC_DisableEventStatus(XMC_SDMMC_t * const sdmmc,uint32_t event)235 void XMC_SDMMC_DisableEventStatus(XMC_SDMMC_t *const sdmmc, uint32_t event)
236 {
237   XMC_ASSERT("XMC_SDMMC_DisableEventStatus: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
238 
239   /* Clear INT status enable register */
240   sdmmc->EN_INT_STATUS_NORM &= (uint16_t)~event;
241   sdmmc->EN_INT_STATUS_ERR &= (uint16_t)~(event >> 16U);
242 }
243 
244 /* Enable SDMMC event */
XMC_SDMMC_EnableEvent(XMC_SDMMC_t * const sdmmc,uint32_t event)245 void XMC_SDMMC_EnableEvent(XMC_SDMMC_t *const sdmmc, uint32_t event)
246 {
247   XMC_ASSERT("XMC_SDMMC_EnableEvent: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
248 
249   XMC_SDMMC_EnableEventStatus(sdmmc, event);
250 
251   sdmmc->EN_INT_SIGNAL_NORM |= (uint16_t)event;
252   sdmmc->EN_INT_SIGNAL_ERR |= (uint16_t)(event >> 16U);
253 }
254 
255 /* Disable SDMMC event without disabling event status */
XMC_SDMMC_DisableEvent(XMC_SDMMC_t * const sdmmc,uint32_t event)256 void XMC_SDMMC_DisableEvent(XMC_SDMMC_t *const sdmmc, uint32_t event)
257 {
258   XMC_ASSERT("XMC_SDMMC_DisableEvent: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
259 
260   /* Clear INT signal enable register */
261   sdmmc->EN_INT_SIGNAL_NORM &= (uint16_t)~event;
262   sdmmc->EN_INT_SIGNAL_ERR &= (uint16_t)~(event >> 16U);
263 }
264 
265 /* Clear SDMMC event(s) */
XMC_SDMMC_ClearEvent(XMC_SDMMC_t * const sdmmc,uint32_t event)266 void XMC_SDMMC_ClearEvent(XMC_SDMMC_t *const sdmmc, uint32_t event)
267 {
268   XMC_ASSERT("XMC_SDMMC_ClearEvent: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
269   XMC_ASSERT("XMC_SDMMC_ClearEvent: Invalid bit-field", !(event & XMC_SDMMC_TARGET_RESP_ERR));
270 
271   sdmmc->INT_STATUS_NORM = (uint16_t)event;
272   sdmmc->INT_STATUS_ERR = (uint16_t)(event >> 16U);
273 }
274 
275 /* Get the status of an SDMMC event */
XMC_SDMMC_GetEvent(XMC_SDMMC_t * const sdmmc,XMC_SDMMC_EVENT_t event)276 bool XMC_SDMMC_GetEvent(XMC_SDMMC_t *const sdmmc, XMC_SDMMC_EVENT_t event)
277 {
278   bool status;
279 
280   XMC_ASSERT("XMC_SDMMC_GetEvent: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
281   XMC_ASSERT("XMC_SDMMC_GetEvent: Invalid SDMMC event", XMC_SDMMC_CHECK_EVENT(event));
282 
283   if (event < XMC_SDMMC_CMD_TIMEOUT_ERR)
284   {
285     status = (bool)(sdmmc->INT_STATUS_NORM & (uint16_t)event);
286   }
287   else
288   {
289     status = (bool)(sdmmc->INT_STATUS_ERR & (uint16_t)((uint32_t)event >> 16U));
290   }
291 
292   return status;
293 }
294 
295 /* Read R2 response (CID, CSD register) */
XMC_SDMMC_GetR2Response(XMC_SDMMC_t * const sdmmc,XMC_SDMMC_RESPONSE_t * const response)296 void XMC_SDMMC_GetR2Response(XMC_SDMMC_t *const sdmmc, XMC_SDMMC_RESPONSE_t *const response)
297 {
298   XMC_ASSERT("XMC_SDMMC_GetR2Response: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
299 
300   response->response_0 = sdmmc->RESPONSE[0];
301   response->response_2 = sdmmc->RESPONSE[1];
302   response->response_4 = sdmmc->RESPONSE[2];
303   response->response_6 = sdmmc->RESPONSE[3];
304 }
305 
306 /* Send SDMMC command */
XMC_SDMMC_SendCommand(XMC_SDMMC_t * const sdmmc,const XMC_SDMMC_COMMAND_t * cmd,uint32_t arg)307 XMC_SDMMC_STATUS_t XMC_SDMMC_SendCommand(XMC_SDMMC_t *const sdmmc, const XMC_SDMMC_COMMAND_t *cmd, uint32_t arg)
308 {
309   XMC_ASSERT("XMC_SDMMC_SendCommand: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
310 
311   sdmmc->ARGUMENT1 = arg;
312   sdmmc->COMMAND = (uint16_t)(*(uint16_t *)cmd);
313 
314   return XMC_SDMMC_STATUS_SUCCESS;
315 }
316 
317 /* Set data transfer mode */
XMC_SDMMC_SetDataTransferMode(XMC_SDMMC_t * const sdmmc,XMC_SDMMC_TRANSFER_MODE_t * const response)318 void XMC_SDMMC_SetDataTransferMode(XMC_SDMMC_t *const sdmmc, XMC_SDMMC_TRANSFER_MODE_t *const response)
319 {
320   XMC_ASSERT("XMC_SDMMC_SetDataTransferMode: Invalid module pointer", XMC_SDMMC_CHECK_MODULE_PTR(sdmmc));
321   XMC_ASSERT("XMC_SDMMC_SetDataTransferMode: Invalid transfer type", XMC_SDMMC_CHECK_TRANSFER_MODE(response->type));
322 
323   /* Block size */
324   sdmmc->BLOCK_SIZE = (uint16_t)(response->block_size);
325 
326   /* Number of blocks */
327   sdmmc->BLOCK_COUNT = (uint16_t)(response->num_blocks);
328 
329   /* Type of data transfer: single, infinite, multiple or stop multiple */
330   sdmmc->TRANSFER_MODE = (uint16_t)((sdmmc->TRANSFER_MODE & (uint16_t)~SDMMC_TRANSFER_MODE_MULTI_BLOCK_SELECT_Msk) |
331                                     ((uint16_t)response->type));
332 
333   /*
334    * Clear block count enable bit; that's only valid for
335    * a multi-block transfer
336    */
337   if (response->type == XMC_SDMMC_TRANSFER_MODE_TYPE_SINGLE)
338   {
339     sdmmc->TRANSFER_MODE &= (uint16_t)~SDMMC_TRANSFER_MODE_BLOCK_COUNT_EN_Msk;
340   }
341 
342   /* Auto CMD configuration */
343   sdmmc->TRANSFER_MODE = (uint16_t)((sdmmc->TRANSFER_MODE & (uint16_t)~SDMMC_TRANSFER_MODE_ACMD_EN_Msk) |
344                                     ((uint16_t)response->auto_cmd << SDMMC_TRANSFER_MODE_ACMD_EN_Pos));
345 }
346 
347 #endif /* #if defined (SDMMC) */
348 
349 /**
350  * @}
351  */
352 
353 /**
354  * @}
355  */
356