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