1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_sdhc.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.sdhc"
18 #endif
19 
20 /*! @brief Clock setting */
21 /* Max SD clock divisor from base clock */
22 #define SDHC_MAX_DVS       ((SDHC_SYSCTL_DVS_MASK >> SDHC_SYSCTL_DVS_SHIFT) + 1U)
23 #define SDHC_PREV_DVS(x)   ((x) -= 1U)
24 #define SDHC_MAX_CLKFS     ((SDHC_SYSCTL_SDCLKFS_MASK >> SDHC_SYSCTL_SDCLKFS_SHIFT) + 1U)
25 #define SDHC_PREV_CLKFS(x) ((x) >>= 1U)
26 
27 /* Typedef for interrupt handler. */
28 typedef void (*sdhc_isr_t)(SDHC_Type *base, sdhc_handle_t *handle);
29 
30 /*! @brief ADMA table configuration */
31 typedef struct _sdhc_adma_table_config
32 {
33     uint32_t *admaTable;     /*!< ADMA table address, can't be null if transfer way is ADMA1/ADMA2 */
34     uint32_t admaTableWords; /*!< ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2 */
35 } sdhc_adma_table_config_t;
36 /*! @brief check flag avalibility */
37 #define IS_SDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
38 /*******************************************************************************
39  * Prototypes
40  ******************************************************************************/
41 /*!
42  * @brief Get the instance.
43  *
44  * @param base SDHC peripheral base address.
45  * @return Instance number.
46  */
47 static uint32_t SDHC_GetInstance(SDHC_Type *base);
48 
49 /*!
50  * @brief Start transfer according to current transfer state
51  *
52  * @param base SDHC peripheral base address.
53  * @param command Command to be sent.
54  * @param data Data to be transferred.
55  * @param DMA mode selection
56  */
57 static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data, sdhc_dma_mode_t dmaMode);
58 
59 /*!
60  * @brief Receive command response
61  *
62  * @param base SDHC peripheral base address.
63  * @param command Command to be sent.
64  */
65 static status_t SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command);
66 
67 /*!
68  * @brief Read DATAPORT when buffer enable bit is set.
69  *
70  * @param base SDHC peripheral base address.
71  * @param data Data to be read.
72  * @param transferredWords The number of data words have been transferred last time transaction.
73  * @return The number of total data words have been transferred after this time transaction.
74  */
75 static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
76 
77 /*!
78  * @brief Read data by using DATAPORT polling way.
79  *
80  * @param base SDHC peripheral base address.
81  * @param data Data to be read.
82  * @retval kStatus_Fail Read DATAPORT failed.
83  * @retval kStatus_Success Operate successfully.
84  */
85 static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
86 
87 /*!
88  * @brief Write DATAPORT when buffer enable bit is set.
89  *
90  * @param base SDHC peripheral base address.
91  * @param data Data to be read.
92  * @param transferredWords The number of data words have been transferred last time.
93  * @return The number of total data words have been transferred after this time transaction.
94  */
95 static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords);
96 
97 /*!
98  * @brief Write data by using DATAPORT polling way.
99  *
100  * @param base SDHC peripheral base address.
101  * @param data Data to be transferred.
102  * @retval kStatus_Fail Write DATAPORT failed.
103  * @retval kStatus_Success Operate successfully.
104  */
105 static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
106 
107 /*!
108  * @brief Send command by using polling way.
109  *
110  * @param base SDHC peripheral base address.
111  * @param command Command to be sent.
112  * @retval kStatus_Fail Send command failed.
113  * @retval kStatus_Success Operate successfully.
114  */
115 static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command);
116 
117 /*!
118  * @brief Transfer data by DATAPORT and polling way.
119  *
120  * @param base SDHC peripheral base address.
121  * @param data Data to be transferred.
122  * @retval kStatus_Fail Transfer data failed.
123  * @retval kStatus_Success Operate successfully.
124  */
125 static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data);
126 
127 /*!
128  * @brief Transfer data by ADMA2 and polling way.
129  *
130  * @param base SDHC peripheral base address.
131  * @param data Data to be transferred.
132  * @retval kStatus_Fail Transfer data failed.
133  * @retval kStatus_Success Operate successfully.
134  */
135 static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data);
136 
137 /*!
138  * @brief Transfer data by polling way.
139  *
140  * @param dmaMode DMA mode.
141  * @param base SDHC peripheral base address.
142  * @param data Data to be transferred.
143  * @retval kStatus_Fail Transfer data failed.
144  * @retval kStatus_InvalidArgument Argument is invalid.
145  * @retval kStatus_Success Operate successfully.
146  */
147 static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data);
148 
149 /*!
150  * @brief Handle card detect interrupt.
151  *
152  * @param base SDHC peripheral base address.
153  * @param handle SDHC handle.
154  * @param interruptFlags Card detect related interrupt flags.
155  */
156 static void SDHC_TransferHandleCardDetect(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
157 
158 /*!
159  * @brief Handle command interrupt.
160  *
161  * @param base SDHC peripheral base address.
162  * @param handle SDHC handle.
163  * @param interruptFlags Command related interrupt flags.
164  */
165 static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
166 
167 /*!
168  * @brief Handle data interrupt.
169  *
170  * @param base SDHC peripheral base address.
171  * @param handle SDHC handle.
172  * @param interruptFlags Data related interrupt flags.
173  */
174 static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags);
175 
176 /*!
177  * @brief Handle SDIO card interrupt signal.
178  *
179  * @param base SDHC peripheral base address.
180  * @param handle SDHC handle.
181  */
182 static void SDHC_TransferHandleSdioInterrupt(SDHC_Type *base, sdhc_handle_t *handle);
183 
184 /*!
185  * @brief Handle SDIO block gap event.
186  *
187  * @param base SDHC peripheral base address.
188  * @param handle SDHC handle.
189  */
190 static void SDHC_TransferHandleSdioBlockGap(SDHC_Type *base, sdhc_handle_t *handle);
191 
192 /*******************************************************************************
193  * Variables
194  ******************************************************************************/
195 /*! @brief SDHC internal handle pointer array */
196 static sdhc_handle_t *s_sdhcHandle[FSL_FEATURE_SOC_SDHC_COUNT];
197 
198 /*! @brief SDHC base pointer array */
199 static SDHC_Type *const s_sdhcBase[] = SDHC_BASE_PTRS;
200 
201 /*! @brief SDHC IRQ name array */
202 static const IRQn_Type s_sdhcIRQ[] = SDHC_IRQS;
203 
204 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
205 /*! @brief SDHC clock array name */
206 static const clock_ip_name_t s_sdhcClock[] = SDHC_CLOCKS;
207 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
208 
209 /* SDHC ISR for transactional APIs. */
210 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
211 static sdhc_isr_t s_sdhcIsr = (sdhc_isr_t)DefaultISR;
212 #else
213 static sdhc_isr_t s_sdhcIsr;
214 #endif
215 
216 /*******************************************************************************
217  * Code
218  ******************************************************************************/
SDHC_GetInstance(SDHC_Type * base)219 static uint32_t SDHC_GetInstance(SDHC_Type *base)
220 {
221     uint8_t instance = 0;
222 
223     while ((instance < ARRAY_SIZE(s_sdhcBase)) && (s_sdhcBase[instance] != base))
224     {
225         instance++;
226     }
227 
228     assert(instance < ARRAY_SIZE(s_sdhcBase));
229 
230     return instance;
231 }
232 
SDHC_StartTransfer(SDHC_Type * base,sdhc_command_t * command,sdhc_data_t * data,sdhc_dma_mode_t dmaMode)233 static void SDHC_StartTransfer(SDHC_Type *base, sdhc_command_t *command, sdhc_data_t *data, sdhc_dma_mode_t dmaMode)
234 {
235     uint32_t flags                            = 0U;
236     sdhc_transfer_config_t sdhcTransferConfig = {0};
237 
238     /* Define the flag corresponding to each response type. */
239     if (command->responseType == kCARD_ResponseTypeR1) /* Response 1 */
240     {
241         flags |= ((uint32_t)kSDHC_ResponseLength48Flag | (uint32_t)kSDHC_EnableCrcCheckFlag |
242                   (uint32_t)kSDHC_EnableIndexCheckFlag);
243     }
244     else if (command->responseType == kCARD_ResponseTypeR1b) /* Response 1 with busy */
245     {
246         flags |= ((uint32_t)kSDHC_ResponseLength48BusyFlag | (uint32_t)kSDHC_EnableCrcCheckFlag |
247                   (uint32_t)kSDHC_EnableIndexCheckFlag);
248     }
249     else if (command->responseType == kCARD_ResponseTypeR2) /* Response 2 */
250     {
251         flags |= ((uint32_t)kSDHC_ResponseLength136Flag | (uint32_t)kSDHC_EnableCrcCheckFlag);
252     }
253     else if (command->responseType == kCARD_ResponseTypeR3) /* Response 3 */
254     {
255         flags |= ((uint32_t)kSDHC_ResponseLength48Flag);
256     }
257     else if (command->responseType == kCARD_ResponseTypeR4) /* Response 4 */
258     {
259         flags |= ((uint32_t)kSDHC_ResponseLength48Flag);
260     }
261     else if (command->responseType == kCARD_ResponseTypeR5) /* Response 5 */
262     {
263         flags |= ((uint32_t)kSDHC_ResponseLength48Flag | (uint32_t)kSDHC_EnableCrcCheckFlag |
264                   (uint32_t)kSDHC_EnableIndexCheckFlag);
265     }
266     else if (command->responseType == kCARD_ResponseTypeR5b) /* Response 5 with busy */
267     {
268         flags |= ((uint32_t)kSDHC_ResponseLength48BusyFlag | (uint32_t)kSDHC_EnableCrcCheckFlag |
269                   (uint32_t)kSDHC_EnableIndexCheckFlag);
270     }
271     else if (command->responseType == kCARD_ResponseTypeR6) /* Response 6 */
272     {
273         flags |= ((uint32_t)kSDHC_ResponseLength48Flag | (uint32_t)kSDHC_EnableCrcCheckFlag |
274                   (uint32_t)kSDHC_EnableIndexCheckFlag);
275     }
276     else if (command->responseType == kCARD_ResponseTypeR7) /* Response 7 */
277     {
278         flags |= ((uint32_t)kSDHC_ResponseLength48Flag | (uint32_t)kSDHC_EnableCrcCheckFlag |
279                   (uint32_t)kSDHC_EnableIndexCheckFlag);
280     }
281     else
282     {
283         /* Intentional empty for kCARD_ResponseTypeNone */
284     }
285 
286     if (command->type == kCARD_CommandTypeAbort)
287     {
288         flags |= (uint32_t)kSDHC_CommandTypeAbortFlag;
289     }
290 
291     if (data != NULL)
292     {
293         flags |= (uint32_t)kSDHC_DataPresentFlag;
294 
295         if (dmaMode != kSDHC_DmaModeNo)
296         {
297             flags |= (uint32_t)kSDHC_EnableDmaFlag;
298         }
299 
300         if (data->rxData != NULL)
301         {
302             flags |= (uint32_t)kSDHC_DataReadFlag;
303         }
304         if (data->blockCount > 1U)
305         {
306             flags |= ((uint32_t)kSDHC_MultipleBlockFlag | (uint32_t)kSDHC_EnableBlockCountFlag);
307             if (data->enableAutoCommand12)
308             {
309                 /* Enable Auto command 12. */
310                 flags |= (uint32_t)kSDHC_EnableAutoCommand12Flag;
311             }
312         }
313 
314         sdhcTransferConfig.dataBlockSize  = data->blockSize;
315         sdhcTransferConfig.dataBlockCount = data->blockCount;
316     }
317     else
318     {
319         sdhcTransferConfig.dataBlockSize  = 0U;
320         sdhcTransferConfig.dataBlockCount = 0U;
321     }
322 
323     sdhcTransferConfig.commandArgument = command->argument;
324     sdhcTransferConfig.commandIndex    = command->index;
325     sdhcTransferConfig.flags           = flags;
326     SDHC_SetTransferConfig(base, &sdhcTransferConfig);
327 }
328 
SDHC_ReceiveCommandResponse(SDHC_Type * base,sdhc_command_t * command)329 static status_t SDHC_ReceiveCommandResponse(SDHC_Type *base, sdhc_command_t *command)
330 {
331     assert(command != NULL);
332 
333     uint32_t response0 = base->CMDRSP[0];
334     uint32_t response1 = base->CMDRSP[1];
335     uint32_t response2 = base->CMDRSP[2];
336 
337     if (command->responseType != kCARD_ResponseTypeNone)
338     {
339         command->response[0U] = response0;
340         if (command->responseType == kCARD_ResponseTypeR2)
341         {
342             /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
343             after removed internal CRC7 and end bit. */
344             command->response[0U] <<= 8U;
345             command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
346             command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
347             command->response[3U] = (base->CMDRSP[3] << 8U) | ((response2 & 0xFF000000U) >> 24U);
348         }
349     }
350 
351     /* check response error flag */
352     if ((command->responseErrorFlags != 0U) &&
353         ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
354          (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
355     {
356         if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
357         {
358             return kStatus_SDHC_SendCommandFailed;
359         }
360     }
361 
362     return kStatus_Success;
363 }
364 
SDHC_ReadDataPort(SDHC_Type * base,sdhc_data_t * data,uint32_t transferredWords)365 static uint32_t SDHC_ReadDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
366 {
367     uint32_t i;
368     uint32_t totalWords;
369     uint32_t wordsCanBeRead; /* The words can be read at this time. */
370     uint32_t readWatermark = ((base->WML & SDHC_WML_RDWML_MASK) >> SDHC_WML_RDWML_SHIFT);
371 
372     /*
373      * Add non aligned access support ,user need make sure your buffer size is big
374      * enough to hold the data,in other words,user need make sure the buffer size
375      * is 4 byte aligned
376      */
377     if (data->blockSize % sizeof(uint32_t) != 0U)
378     {
379         data->blockSize +=
380             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
381     }
382 
383     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
384 
385     /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
386     if (readWatermark >= totalWords)
387     {
388         wordsCanBeRead = totalWords;
389     }
390     /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
391     transfers watermark level words. */
392     else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
393     {
394         wordsCanBeRead = readWatermark;
395     }
396     /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers left
397     words. */
398     else
399     {
400         wordsCanBeRead = (totalWords - transferredWords);
401     }
402 
403     i = 0U;
404     while (i < wordsCanBeRead)
405     {
406         data->rxData[transferredWords++] = SDHC_ReadData(base);
407         i++;
408     }
409 
410     return transferredWords;
411 }
412 
SDHC_ReadByDataPortBlocking(SDHC_Type * base,sdhc_data_t * data)413 static status_t SDHC_ReadByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
414 {
415     uint32_t totalWords;
416     uint32_t transferredWords = 0U;
417     status_t error            = kStatus_Success;
418 
419     /*
420      * Add non aligned access support ,user need make sure your buffer size is big
421      * enough to hold the data,in other words,user need make sure the buffer size
422      * is 4 byte aligned
423      */
424     if (data->blockSize % sizeof(uint32_t) != 0U)
425     {
426         data->blockSize +=
427             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
428     }
429 
430     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
431 
432     while ((error == kStatus_Success) && (transferredWords < totalWords))
433     {
434         while (!(IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base),
435                                   ((uint32_t)kSDHC_BufferReadReadyFlag | (uint32_t)kSDHC_DataErrorFlag))))
436         {
437         }
438 
439         if (IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base), kSDHC_DataErrorFlag))
440         {
441             if (!(data->enableIgnoreError))
442             {
443                 error = kStatus_Fail;
444             }
445         }
446         if (error == kStatus_Success)
447         {
448             transferredWords = SDHC_ReadDataPort(base, data, transferredWords);
449         }
450         /* clear buffer ready and error */
451         SDHC_ClearInterruptStatusFlags(base, (uint32_t)kSDHC_BufferReadReadyFlag | (uint32_t)kSDHC_DataErrorFlag);
452     }
453 
454     /* Clear data complete flag after the last read operation. */
455     SDHC_ClearInterruptStatusFlags(base, (uint32_t)kSDHC_DataCompleteFlag | (uint32_t)kSDHC_DataErrorFlag);
456 
457     return error;
458 }
459 
SDHC_WriteDataPort(SDHC_Type * base,sdhc_data_t * data,uint32_t transferredWords)460 static uint32_t SDHC_WriteDataPort(SDHC_Type *base, sdhc_data_t *data, uint32_t transferredWords)
461 {
462     uint32_t i;
463     uint32_t totalWords;
464     uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
465     uint32_t writeWatermark = ((base->WML & SDHC_WML_WRWML_MASK) >> SDHC_WML_WRWML_SHIFT);
466 
467     /*
468      * Add non aligned access support ,user need make sure your buffer size is big
469      * enough to hold the data,in other words,user need make sure the buffer size
470      * is 4 byte aligned
471      */
472     if (data->blockSize % sizeof(uint32_t) != 0U)
473     {
474         data->blockSize +=
475             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
476     }
477 
478     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
479 
480     /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
481     if (writeWatermark >= totalWords)
482     {
483         wordsCanBeWrote = totalWords;
484     }
485     /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
486     transfers watermark level words. */
487     else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
488     {
489         wordsCanBeWrote = writeWatermark;
490     }
491     /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
492     words. */
493     else
494     {
495         wordsCanBeWrote = (totalWords - transferredWords);
496     }
497 
498     i = 0U;
499     while (i < wordsCanBeWrote)
500     {
501         SDHC_WriteData(base, data->txData[transferredWords++]);
502         i++;
503     }
504 
505     return transferredWords;
506 }
507 
SDHC_WriteByDataPortBlocking(SDHC_Type * base,sdhc_data_t * data)508 static status_t SDHC_WriteByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
509 {
510     uint32_t totalWords;
511     uint32_t transferredWords = 0U;
512     status_t error            = kStatus_Success;
513 
514     /*
515      * Add non aligned access support ,user need make sure your buffer size is big
516      * enough to hold the data,in other words,user need make sure the buffer size
517      * is 4 byte aligned
518      */
519     if (data->blockSize % sizeof(uint32_t) != 0U)
520     {
521         data->blockSize +=
522             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
523     }
524 
525     totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
526 
527     while ((error == kStatus_Success) && (transferredWords < totalWords))
528     {
529         while (!(IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base),
530                                   ((uint32_t)kSDHC_BufferWriteReadyFlag | (uint32_t)kSDHC_DataErrorFlag))))
531         {
532         }
533 
534         if (IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base), kSDHC_DataErrorFlag))
535         {
536             if (!(data->enableIgnoreError))
537             {
538                 error = kStatus_Fail;
539             }
540         }
541         if (error == kStatus_Success)
542         {
543             transferredWords = SDHC_WriteDataPort(base, data, transferredWords);
544         }
545 
546         /* Clear buffer enable flag to trigger transfer. Clear error flag when SDHC encounter error. */
547         SDHC_ClearInterruptStatusFlags(base, ((uint32_t)kSDHC_BufferWriteReadyFlag | (uint32_t)kSDHC_DataErrorFlag));
548     }
549 
550     /* Wait write data complete or data transfer error after the last writing operation. */
551     while (!(IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base),
552                               ((uint32_t)kSDHC_DataCompleteFlag | (uint32_t)kSDHC_DataErrorFlag))))
553     {
554     }
555     if (IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base), kSDHC_DataErrorFlag))
556     {
557         if (!(data->enableIgnoreError))
558         {
559             error = kStatus_Fail;
560         }
561     }
562 
563     SDHC_ClearInterruptStatusFlags(base, ((uint32_t)kSDHC_DataCompleteFlag | (uint32_t)kSDHC_DataErrorFlag));
564 
565     return error;
566 }
567 
SDHC_SendCommandBlocking(SDHC_Type * base,sdhc_command_t * command)568 static status_t SDHC_SendCommandBlocking(SDHC_Type *base, sdhc_command_t *command)
569 {
570     status_t error = kStatus_Success;
571 
572     /* Wait command complete or SDHC encounters error. */
573     while (!(IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base),
574                               ((uint32_t)kSDHC_CommandCompleteFlag | (uint32_t)kSDHC_CommandErrorFlag))))
575     {
576     }
577 
578     if (IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base), kSDHC_CommandErrorFlag))
579     {
580         error = kStatus_Fail;
581     }
582     /* Receive response when command completes successfully. */
583     if (error == kStatus_Success)
584     {
585         error = SDHC_ReceiveCommandResponse(base, command);
586     }
587 
588     SDHC_ClearInterruptStatusFlags(base, ((uint32_t)kSDHC_CommandCompleteFlag | (uint32_t)kSDHC_CommandErrorFlag));
589 
590     return error;
591 }
592 
SDHC_TransferByDataPortBlocking(SDHC_Type * base,sdhc_data_t * data)593 static status_t SDHC_TransferByDataPortBlocking(SDHC_Type *base, sdhc_data_t *data)
594 {
595     status_t error = kStatus_Success;
596 
597     if (data->rxData != NULL)
598     {
599         error = SDHC_ReadByDataPortBlocking(base, data);
600         if (error != kStatus_Success)
601         {
602             return error;
603         }
604     }
605     else
606     {
607         error = SDHC_WriteByDataPortBlocking(base, data);
608         if (error != kStatus_Success)
609         {
610             return error;
611         }
612     }
613 
614     return kStatus_Success;
615 }
616 
SDHC_TransferByAdma2Blocking(SDHC_Type * base,sdhc_data_t * data)617 static status_t SDHC_TransferByAdma2Blocking(SDHC_Type *base, sdhc_data_t *data)
618 {
619     status_t error = kStatus_Success;
620 
621     /* Wait data complete or SDHC encounters error. */
622     while (!(IS_SDHC_FLAG_SET(
623         SDHC_GetInterruptStatusFlags(base),
624         ((uint32_t)kSDHC_DataCompleteFlag | (uint32_t)kSDHC_DataErrorFlag | (uint32_t)kSDHC_DmaErrorFlag))))
625     {
626     }
627     if (IS_SDHC_FLAG_SET(SDHC_GetInterruptStatusFlags(base),
628                          ((uint32_t)kSDHC_DataErrorFlag | (uint32_t)kSDHC_DmaErrorFlag)))
629     {
630         if (!(data->enableIgnoreError))
631         {
632             error = kStatus_Fail;
633         }
634     }
635     SDHC_ClearInterruptStatusFlags(base, ((uint32_t)kSDHC_DataCompleteFlag | (uint32_t)kSDHC_DmaCompleteFlag |
636                                           (uint32_t)kSDHC_DataErrorFlag | (uint32_t)kSDHC_DmaErrorFlag));
637 
638     return error;
639 }
640 
641 #if defined FSL_SDHC_ENABLE_ADMA1
642 #define SDHC_TransferByAdma1Blocking(base, data) SDHC_TransferByAdma2Blocking(base, data)
643 #endif /* FSL_SDHC_ENABLE_ADMA1 */
644 
SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode,SDHC_Type * base,sdhc_data_t * data)645 static status_t SDHC_TransferDataBlocking(sdhc_dma_mode_t dmaMode, SDHC_Type *base, sdhc_data_t *data)
646 {
647     status_t error = kStatus_Success;
648 
649     if (dmaMode == kSDHC_DmaModeNo)
650     {
651         error = SDHC_TransferByDataPortBlocking(base, data);
652         if (error != kStatus_Success)
653         {
654             return error;
655         }
656     }
657 #if defined FSL_SDHC_ENABLE_ADMA1
658     else if (dmaMode == kSDHC_DmaModeAdma1)
659     {
660         error = SDHC_TransferByAdma1Blocking(base, data);
661         if (error != kStatus_Success)
662         {
663             return error;
664         }
665     }
666 #endif /* FSL_SDHC_ENABLE_ADMA1 */
667 
668     /*kSDHC_DmaModeAdma2*/
669     else
670     {
671         error = SDHC_TransferByAdma2Blocking(base, data);
672         if (error != kStatus_Success)
673         {
674             return error;
675         }
676     }
677 
678     return kStatus_Success;
679 }
680 
SDHC_TransferHandleCardDetect(SDHC_Type * base,sdhc_handle_t * handle,uint32_t interruptFlags)681 static void SDHC_TransferHandleCardDetect(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
682 {
683     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_CardInsertionFlag))
684     {
685         if (handle->callback.CardInserted != NULL)
686         {
687             handle->callback.CardInserted(base, handle->userData);
688         }
689     }
690     else
691     {
692         if (handle->callback.CardRemoved != NULL)
693         {
694             handle->callback.CardRemoved(base, handle->userData);
695         }
696     }
697 }
698 
SDHC_TransferHandleCommand(SDHC_Type * base,sdhc_handle_t * handle,uint32_t interruptFlags)699 static void SDHC_TransferHandleCommand(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
700 {
701     assert(handle->command != NULL);
702 
703     if ((IS_SDHC_FLAG_SET(interruptFlags, kSDHC_CommandErrorFlag)) && (handle->data == NULL) &&
704         (handle->callback.TransferComplete != NULL))
705     {
706         handle->callback.TransferComplete(base, handle, kStatus_SDHC_SendCommandFailed, handle->userData);
707     }
708     else
709     {
710         /* Receive response */
711         if (kStatus_Success != SDHC_ReceiveCommandResponse(base, handle->command))
712         {
713             if (handle->callback.TransferComplete != NULL)
714             {
715                 handle->callback.TransferComplete(base, handle, kStatus_SDHC_SendCommandFailed, handle->userData);
716             }
717         }
718         else
719         {
720             if (handle->callback.TransferComplete != NULL)
721             {
722                 handle->callback.TransferComplete(base, handle, kStatus_SDHC_TransferCommandComplete, handle->userData);
723             }
724         }
725     }
726 
727     SDHC_DisableInterruptSignal(base, kSDHC_CommandFlag);
728     handle->command = NULL;
729 }
730 
SDHC_TransferHandleData(SDHC_Type * base,sdhc_handle_t * handle,uint32_t interruptFlags)731 static void SDHC_TransferHandleData(SDHC_Type *base, sdhc_handle_t *handle, uint32_t interruptFlags)
732 {
733     assert(handle->data != NULL);
734 
735     status_t transferStatus   = kStatus_SDHC_BusyTransferring;
736     uint32_t transferredWords = handle->transferredWords;
737 
738     if ((!(handle->data->enableIgnoreError)) &&
739         (IS_SDHC_FLAG_SET(interruptFlags, ((uint32_t)kSDHC_DataErrorFlag | (uint32_t)kSDHC_DmaErrorFlag))))
740     {
741         transferStatus = kStatus_SDHC_TransferDataFailed;
742     }
743     else
744     {
745         if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_BufferReadReadyFlag))
746         {
747             handle->transferredWords = SDHC_ReadDataPort(base, handle->data, transferredWords);
748         }
749         else if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_BufferWriteReadyFlag))
750         {
751             handle->transferredWords = SDHC_WriteDataPort(base, handle->data, transferredWords);
752         }
753         else
754         {
755             /* Intentional empty */
756         }
757 
758         if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_DataCompleteFlag))
759         {
760             transferStatus = kStatus_SDHC_TransferDataComplete;
761         }
762     }
763 
764     if ((transferStatus != kStatus_SDHC_BusyTransferring) && (handle->callback.TransferComplete != NULL))
765     {
766         handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
767         SDHC_DisableInterruptSignal(base, (uint32_t)kSDHC_DataFlag | (uint32_t)kSDHC_DataDMAFlag);
768         handle->data = NULL;
769     }
770 }
771 
SDHC_TransferHandleSdioInterrupt(SDHC_Type * base,sdhc_handle_t * handle)772 static void SDHC_TransferHandleSdioInterrupt(SDHC_Type *base, sdhc_handle_t *handle)
773 {
774     if (handle->callback.SdioInterrupt != NULL)
775     {
776         handle->callback.SdioInterrupt(base, handle->userData);
777     }
778 }
779 
SDHC_TransferHandleSdioBlockGap(SDHC_Type * base,sdhc_handle_t * handle)780 static void SDHC_TransferHandleSdioBlockGap(SDHC_Type *base, sdhc_handle_t *handle)
781 {
782     if (handle->callback.SdioBlockGap != NULL)
783     {
784         handle->callback.SdioBlockGap(base, handle->userData);
785     }
786 }
787 
788 /*!
789  * brief SDHC module initialization function.
790  *
791  * Configures the SDHC according to the user configuration.
792  *
793  * Example:
794    code
795    sdhc_config_t config;
796    config.cardDetectDat3 = false;
797    config.endianMode = kSDHC_EndianModeLittle;
798    config.dmaMode = kSDHC_DmaModeAdma2;
799    config.readWatermarkLevel = 128U;
800    config.writeWatermarkLevel = 128U;
801    SDHC_Init(SDHC, &config);
802    endcode
803  *
804  * param base SDHC peripheral base address.
805  * param config SDHC configuration information.
806  * retval kStatus_Success Operate successfully.
807  */
SDHC_Init(SDHC_Type * base,const sdhc_config_t * config)808 void SDHC_Init(SDHC_Type *base, const sdhc_config_t *config)
809 {
810     assert(config != NULL);
811 #if !defined FSL_SDHC_ENABLE_ADMA1
812     assert(config->dmaMode != kSDHC_DmaModeAdma1);
813 #endif /* FSL_SDHC_ENABLE_ADMA1 */
814     assert((config->writeWatermarkLevel >= 1UL) && (config->writeWatermarkLevel <= 128UL));
815     assert((config->readWatermarkLevel >= 1UL) && (config->readWatermarkLevel <= 128UL));
816 
817     uint32_t proctl;
818     uint32_t wml;
819 
820 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
821     /* Enable SDHC clock. */
822     CLOCK_EnableClock(s_sdhcClock[SDHC_GetInstance(base)]);
823 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
824 
825     /* Reset SDHC. */
826     base->SYSCTL |= SDHC_SYSCTL_RSTA_MASK | SDHC_SYSCTL_RSTC_MASK | SDHC_SYSCTL_RSTD_MASK;
827 
828     proctl = base->PROCTL;
829     wml    = base->WML;
830 
831     proctl &= ~(SDHC_PROCTL_D3CD_MASK | SDHC_PROCTL_EMODE_MASK | SDHC_PROCTL_DMAS_MASK);
832     /* Set DAT3 as card detection pin */
833     if (config->cardDetectDat3)
834     {
835         proctl |= SDHC_PROCTL_D3CD_MASK;
836     }
837     /* Endian mode and DMA mode */
838     proctl |= (SDHC_PROCTL_EMODE(config->endianMode) | SDHC_PROCTL_DMAS(config->dmaMode));
839 
840     /* Watermark level */
841     wml &= ~(SDHC_WML_RDWML_MASK | SDHC_WML_WRWML_MASK);
842     wml |= (SDHC_WML_RDWML(config->readWatermarkLevel) | SDHC_WML_WRWML(config->writeWatermarkLevel));
843 
844     base->WML    = wml;
845     base->PROCTL = proctl;
846 
847     /* Disable all clock auto gated off feature because of DAT0 line logic(card buffer full status) can't be updated
848     correctly when clock auto gated off is enabled. */
849     base->SYSCTL |= (SDHC_SYSCTL_PEREN_MASK | SDHC_SYSCTL_HCKEN_MASK | SDHC_SYSCTL_IPGEN_MASK);
850 
851     /* Enable interrupt status but doesn't enable interrupt signal, clear all the interrupt status */
852     base->IRQSTATEN = kSDHC_AllInterruptFlags;
853     base->IRQSIGEN  = 0U;
854     base->IRQSTAT   = kSDHC_AllInterruptFlags;
855 }
856 
857 /*!
858  * brief Deinitializes the SDHC.
859  *
860  * param base SDHC peripheral base address.
861  */
SDHC_Deinit(SDHC_Type * base)862 void SDHC_Deinit(SDHC_Type *base)
863 {
864 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
865     /* Disable clock. */
866     CLOCK_DisableClock(s_sdhcClock[SDHC_GetInstance(base)]);
867 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
868 }
869 
870 /*!
871  * brief Resets the SDHC.
872  *
873  * param base SDHC peripheral base address.
874  * param mask The reset type mask(_sdhc_reset).
875  * param timeout Timeout for reset.
876  * retval true Reset successfully.
877  * retval false Reset failed.
878  */
SDHC_Reset(SDHC_Type * base,uint32_t mask,uint32_t timeout)879 bool SDHC_Reset(SDHC_Type *base, uint32_t mask, uint32_t timeout)
880 {
881     base->SYSCTL |= (mask & (SDHC_SYSCTL_RSTA_MASK | SDHC_SYSCTL_RSTC_MASK | SDHC_SYSCTL_RSTD_MASK));
882     /* Delay some time to wait reset success. */
883     while (IS_SDHC_FLAG_SET(base->SYSCTL, mask))
884     {
885         if (timeout == 0UL)
886         {
887             break;
888         }
889         timeout--;
890     }
891 
892     return (timeout == 0UL ? false : true);
893 }
894 
895 /*!
896  * brief Gets the capability information.
897  *
898  * param base SDHC peripheral base address.
899  * param capability Structure to save capability information.
900  */
SDHC_GetCapability(SDHC_Type * base,sdhc_capability_t * capability)901 void SDHC_GetCapability(SDHC_Type *base, sdhc_capability_t *capability)
902 {
903     assert(capability != NULL);
904 
905     uint32_t htCapability;
906     uint32_t hostVer;
907     uint32_t maxBlockLength;
908 
909     hostVer      = base->HOSTVER;
910     htCapability = base->HTCAPBLT;
911 
912     /* Get the capability of SDHC. */
913     capability->specVersion    = ((hostVer & SDHC_HOSTVER_SVN_MASK) >> SDHC_HOSTVER_SVN_SHIFT);
914     capability->vendorVersion  = ((hostVer & SDHC_HOSTVER_VVN_MASK) >> SDHC_HOSTVER_VVN_SHIFT);
915     maxBlockLength             = ((htCapability & SDHC_HTCAPBLT_MBL_MASK) >> SDHC_HTCAPBLT_MBL_SHIFT);
916     capability->maxBlockLength = (512UL << maxBlockLength);
917     /* Other attributes not in HTCAPBLT register. */
918     capability->maxBlockCount = SDHC_MAX_BLOCK_COUNT;
919     capability->flags = (htCapability & ((uint32_t)kSDHC_SupportAdmaFlag | (uint32_t)kSDHC_SupportHighSpeedFlag |
920                                          (uint32_t)kSDHC_SupportDmaFlag | (uint32_t)kSDHC_SupportSuspendResumeFlag |
921                                          (uint32_t)kSDHC_SupportV330Flag));
922 #if defined FSL_FEATURE_SDHC_HAS_V300_SUPPORT && FSL_FEATURE_SDHC_HAS_V300_SUPPORT
923     capability->flags |= (htCapability & (uint32_t)kSDHC_SupportV300Flag);
924 #endif
925 #if defined FSL_FEATURE_SDHC_HAS_V180_SUPPORT && FSL_FEATURE_SDHC_HAS_V180_SUPPORT
926     capability->flags |= (htCapability & (uint32_t)kSDHC_SupportV180Flag);
927 #endif
928     /* eSDHC on all kinetis boards will support 4/8 bit data bus width. */
929     capability->flags |= ((uint32_t)kSDHC_Support4BitFlag | (uint32_t)kSDHC_Support8BitFlag);
930 }
931 
932 /*!
933  * brief Sets the SD bus clock frequency.
934  *
935  * param base SDHC peripheral base address.
936  * param srcClock_Hz SDHC source clock frequency united in Hz.
937  * param busClock_Hz SD bus clock frequency united in Hz.
938  *
939  * return The nearest frequency of busClock_Hz configured to SD bus.
940  */
SDHC_SetSdClock(SDHC_Type * base,uint32_t srcClock_Hz,uint32_t busClock_Hz)941 uint32_t SDHC_SetSdClock(SDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
942 {
943     assert(srcClock_Hz != 0U);
944     assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz));
945 
946     uint32_t totalDiv         = 0U;
947     uint32_t divisor          = 0U;
948     uint32_t prescaler        = 0U;
949     uint32_t sysctl           = 0U;
950     uint32_t nearestFrequency = 0U;
951 
952     /* calucate total divisor first */
953     totalDiv = srcClock_Hz / busClock_Hz;
954 
955     if (totalDiv > (SDHC_MAX_CLKFS * SDHC_MAX_DVS))
956     {
957         return 0UL;
958     }
959 
960     if (totalDiv != 0U)
961     {
962         /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
963         if ((srcClock_Hz / totalDiv) > busClock_Hz)
964         {
965             totalDiv++;
966         }
967 
968         /* divide the total divisor to div and prescaler */
969         if (totalDiv > SDHC_MAX_DVS)
970         {
971             prescaler = totalDiv / SDHC_MAX_DVS;
972             /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
973             while (((SDHC_MAX_CLKFS % prescaler) != 0U) || (prescaler == 1U))
974             {
975                 prescaler++;
976             }
977             /* calucate the divisor */
978             divisor = totalDiv / prescaler;
979             /* fine tuning the divisor until divisor * prescaler >= totalDiv */
980             while ((divisor * prescaler) < totalDiv)
981             {
982                 divisor++;
983             }
984 
985             nearestFrequency = srcClock_Hz / (divisor == 0U ? 1U : divisor) / prescaler;
986         }
987         else
988         {
989             divisor          = totalDiv;
990             prescaler        = 0U;
991             nearestFrequency = srcClock_Hz / divisor;
992         }
993     }
994     /* in this condition , srcClock_Hz = busClock_Hz, */
995     else
996     {
997         /* total divider = 1U */
998         divisor          = 0U;
999         prescaler        = 0U;
1000         nearestFrequency = srcClock_Hz;
1001     }
1002 
1003     /* calucate the value write to register */
1004     if (divisor != 0U)
1005     {
1006         SDHC_PREV_DVS(divisor);
1007     }
1008     /* calucate the value write to register */
1009     if (prescaler != 0U)
1010     {
1011         SDHC_PREV_CLKFS(prescaler);
1012     }
1013 
1014     /* Disable SD clock. It should be disabled before changing the SD clock frequency.*/
1015     base->SYSCTL &= ~SDHC_SYSCTL_SDCLKEN_MASK;
1016 
1017     /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
1018     sysctl = base->SYSCTL;
1019     sysctl &= ~(SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK | SDHC_SYSCTL_DTOCV_MASK);
1020     sysctl |= (SDHC_SYSCTL_DVS(divisor) | SDHC_SYSCTL_SDCLKFS(prescaler) | SDHC_SYSCTL_DTOCV(0xEU));
1021     base->SYSCTL = sysctl;
1022 
1023     /* Wait until the SD clock is stable. */
1024     while (!(IS_SDHC_FLAG_SET(base->PRSSTAT, SDHC_PRSSTAT_SDSTB_MASK)))
1025     {
1026     }
1027     /* Enable the SD clock. */
1028     base->SYSCTL |= SDHC_SYSCTL_SDCLKEN_MASK;
1029 
1030     return nearestFrequency;
1031 }
1032 
1033 /*!
1034  * brief Sends 80 clocks to the card to set it to the active state.
1035  *
1036  * This function must be called each time the card is inserted to ensure that the card can receive the command
1037  * correctly.
1038  *
1039  * param base SDHC peripheral base address.
1040  * param timeout Timeout to initialize card.
1041  * retval true Set card active successfully.
1042  * retval false Set card active failed.
1043  */
SDHC_SetCardActive(SDHC_Type * base,uint32_t timeout)1044 bool SDHC_SetCardActive(SDHC_Type *base, uint32_t timeout)
1045 {
1046     base->SYSCTL |= SDHC_SYSCTL_INITA_MASK;
1047     /* Delay some time to wait card become active state. */
1048     while (IS_SDHC_FLAG_SET(base->SYSCTL, SDHC_SYSCTL_INITA_MASK))
1049     {
1050         if (timeout == 0UL)
1051         {
1052             break;
1053         }
1054         timeout--;
1055     }
1056 
1057     return (timeout == 0UL ? false : true);
1058 }
1059 
1060 /*!
1061  * brief Sets the card transfer-related configuration.
1062  *
1063  * This function fills the card transfer-related command argument/transfer flag/data size. The command and data are sent
1064  by
1065  * SDHC after calling this function.
1066  *
1067  * Example:
1068    code
1069    sdhc_transfer_config_t transferConfig;
1070    transferConfig.dataBlockSize = 512U;
1071    transferConfig.dataBlockCount = 2U;
1072    transferConfig.commandArgument = 0x01AAU;
1073    transferConfig.commandIndex = 8U;
1074    transferConfig.flags |= (kSDHC_EnableDmaFlag | kSDHC_EnableAutoCommand12Flag | kSDHC_MultipleBlockFlag);
1075    SDHC_SetTransferConfig(SDHC, &transferConfig);
1076    endcode
1077  *
1078  * param base SDHC peripheral base address.
1079  * param config Command configuration structure.
1080  */
SDHC_SetTransferConfig(SDHC_Type * base,const sdhc_transfer_config_t * config)1081 void SDHC_SetTransferConfig(SDHC_Type *base, const sdhc_transfer_config_t *config)
1082 {
1083     assert(config != NULL);
1084     assert(config->dataBlockSize <= (SDHC_BLKATTR_BLKSIZE_MASK >> SDHC_BLKATTR_BLKSIZE_SHIFT));
1085     assert(config->dataBlockCount <= (SDHC_BLKATTR_BLKCNT_MASK >> SDHC_BLKATTR_BLKCNT_SHIFT));
1086 
1087     base->BLKATTR = ((base->BLKATTR & ~(SDHC_BLKATTR_BLKSIZE_MASK | SDHC_BLKATTR_BLKCNT_MASK)) |
1088                      (SDHC_BLKATTR_BLKSIZE(config->dataBlockSize) | SDHC_BLKATTR_BLKCNT(config->dataBlockCount)));
1089     base->CMDARG  = config->commandArgument;
1090     base->XFERTYP = (((config->commandIndex << SDHC_XFERTYP_CMDINX_SHIFT) & SDHC_XFERTYP_CMDINX_MASK) |
1091                      (config->flags & (SDHC_XFERTYP_DMAEN_MASK | SDHC_XFERTYP_MSBSEL_MASK | SDHC_XFERTYP_DPSEL_MASK |
1092                                        SDHC_XFERTYP_CMDTYP_MASK | SDHC_XFERTYP_BCEN_MASK | SDHC_XFERTYP_CICEN_MASK |
1093                                        SDHC_XFERTYP_CCCEN_MASK | SDHC_XFERTYP_RSPTYP_MASK | SDHC_XFERTYP_DTDSEL_MASK |
1094                                        SDHC_XFERTYP_AC12EN_MASK)));
1095 }
1096 
1097 /*!
1098  * brief Enables or disables the SDIO card control.
1099  *
1100  * param base SDHC peripheral base address.
1101  * param mask SDIO card control flags mask(_sdhc_sdio_control_flag).
1102  * param enable True to enable, false to disable.
1103  */
SDHC_EnableSdioControl(SDHC_Type * base,uint32_t mask,bool enable)1104 void SDHC_EnableSdioControl(SDHC_Type *base, uint32_t mask, bool enable)
1105 {
1106     uint32_t proctl = base->PROCTL;
1107     uint32_t vendor = base->VENDOR;
1108 
1109     if (enable)
1110     {
1111         if (IS_SDHC_FLAG_SET(mask, kSDHC_StopAtBlockGapFlag))
1112         {
1113             proctl |= SDHC_PROCTL_SABGREQ_MASK;
1114         }
1115         if (IS_SDHC_FLAG_SET(mask, kSDHC_ReadWaitControlFlag))
1116         {
1117             proctl |= SDHC_PROCTL_RWCTL_MASK;
1118         }
1119         if (IS_SDHC_FLAG_SET(mask, kSDHC_InterruptAtBlockGapFlag))
1120         {
1121             proctl |= SDHC_PROCTL_IABG_MASK;
1122         }
1123         if (IS_SDHC_FLAG_SET(mask, kSDHC_ExactBlockNumberReadFlag))
1124         {
1125             vendor |= SDHC_VENDOR_EXBLKNU_MASK;
1126         }
1127     }
1128     else
1129     {
1130         if (IS_SDHC_FLAG_SET(mask, kSDHC_StopAtBlockGapFlag))
1131         {
1132             proctl &= ~SDHC_PROCTL_SABGREQ_MASK;
1133         }
1134         if (IS_SDHC_FLAG_SET(mask, kSDHC_ReadWaitControlFlag))
1135         {
1136             proctl &= ~SDHC_PROCTL_RWCTL_MASK;
1137         }
1138         if (IS_SDHC_FLAG_SET(mask, kSDHC_InterruptAtBlockGapFlag))
1139         {
1140             proctl &= ~SDHC_PROCTL_IABG_MASK;
1141         }
1142         if (IS_SDHC_FLAG_SET(mask, kSDHC_ExactBlockNumberReadFlag))
1143         {
1144             vendor &= ~SDHC_VENDOR_EXBLKNU_MASK;
1145         }
1146     }
1147 
1148     base->PROCTL = proctl;
1149     base->VENDOR = vendor;
1150 }
1151 
1152 /*!
1153  * brief Configures the MMC boot feature.
1154  *
1155  * Example:
1156    code
1157    sdhc_boot_config_t config;
1158    config.ackTimeoutCount = 4;
1159    config.bootMode = kSDHC_BootModeNormal;
1160    config.blockCount = 5;
1161    config.enableBootAck = true;
1162    config.enableBoot = true;
1163    config.enableAutoStopAtBlockGap = true;
1164    SDHC_SetMmcBootConfig(SDHC, &config);
1165    endcode
1166  *
1167  * param base SDHC peripheral base address.
1168  * param config The MMC boot configuration information.
1169  */
SDHC_SetMmcBootConfig(SDHC_Type * base,const sdhc_boot_config_t * config)1170 void SDHC_SetMmcBootConfig(SDHC_Type *base, const sdhc_boot_config_t *config)
1171 {
1172     assert(config != NULL);
1173     assert(config->ackTimeoutCount <= (SDHC_MMCBOOT_DTOCVACK_MASK >> SDHC_MMCBOOT_DTOCVACK_SHIFT));
1174     assert(config->blockCount <= (SDHC_MMCBOOT_BOOTBLKCNT_MASK >> SDHC_MMCBOOT_BOOTBLKCNT_SHIFT));
1175 
1176     uint32_t mmcboot = 0U;
1177 
1178     mmcboot = (SDHC_MMCBOOT_DTOCVACK(config->ackTimeoutCount) | SDHC_MMCBOOT_BOOTMODE(config->bootMode) |
1179                SDHC_MMCBOOT_BOOTBLKCNT(config->blockCount));
1180     if (config->enableBootAck)
1181     {
1182         mmcboot |= SDHC_MMCBOOT_BOOTACK_MASK;
1183     }
1184     if (config->enableBoot)
1185     {
1186         mmcboot |= SDHC_MMCBOOT_BOOTEN_MASK;
1187     }
1188     if (config->enableAutoStopAtBlockGap)
1189     {
1190         mmcboot |= SDHC_MMCBOOT_AUTOSABGEN_MASK;
1191     }
1192     base->MMCBOOT = mmcboot;
1193 }
1194 
1195 /*!
1196  * brief Sets the ADMA descriptor table configuration.
1197  *
1198  * param base SDHC peripheral base address.
1199  * param dmaMode DMA mode.
1200  * param table ADMA table address.
1201  * param tableWords ADMA table buffer length united as Words.
1202  * param data Data buffer address.
1203  * param dataBytes Data length united as bytes.
1204  * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1205  * retval kStatus_Success Operate successfully.
1206  */
SDHC_SetAdmaTableConfig(SDHC_Type * base,sdhc_dma_mode_t dmaMode,uint32_t * table,uint32_t tableWords,const uint32_t * data,uint32_t dataBytes)1207 status_t SDHC_SetAdmaTableConfig(SDHC_Type *base,
1208                                  sdhc_dma_mode_t dmaMode,
1209                                  uint32_t *table,
1210                                  uint32_t tableWords,
1211                                  const uint32_t *data,
1212                                  uint32_t dataBytes)
1213 {
1214     status_t error               = kStatus_Success;
1215     const uint32_t *startAddress = data;
1216     uint32_t entries;
1217     uint32_t i;
1218 #if defined FSL_SDHC_ENABLE_ADMA1
1219     sdhc_adma1_descriptor_t *adma1EntryAddress;
1220 #endif
1221     sdhc_adma2_descriptor_t *adma2EntryAddress;
1222 
1223     if ((((table == NULL) || (tableWords == 0UL)) &&
1224          ((dmaMode == kSDHC_DmaModeAdma1) || (dmaMode == kSDHC_DmaModeAdma2))) ||
1225         (data == NULL) || (dataBytes == 0UL)
1226 #if !defined FSL_SDHC_ENABLE_ADMA1
1227         || (dmaMode == kSDHC_DmaModeAdma1)
1228 #endif
1229     )
1230     {
1231         error = kStatus_InvalidArgument;
1232     }
1233     else if (((dmaMode == kSDHC_DmaModeAdma2) && (((uint32_t)startAddress % SDHC_ADMA2_LENGTH_ALIGN) != 0UL))
1234 #if defined FSL_SDHC_ENABLE_ADMA1
1235              || ((dmaMode == kSDHC_DmaModeAdma1) && (((uint32_t)startAddress % SDHC_ADMA1_LENGTH_ALIGN) != 0UL))
1236 #endif
1237     )
1238     {
1239         error = kStatus_SDHC_DMADataBufferAddrNotAlign;
1240     }
1241     else
1242     {
1243 #if defined FSL_SDHC_ENABLE_ADMA1
1244         if (dmaMode == kSDHC_DmaModeAdma1)
1245         {
1246             /*
1247              * Add non aligned access support ,user need make sure your buffer size is big
1248              * enough to hold the data,in other words,user need make sure the buffer size
1249              * is 4 byte aligned
1250              */
1251             if (dataBytes % sizeof(uint32_t) != 0U)
1252             {
1253                 dataBytes +=
1254                     sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
1255             }
1256 
1257             /* Check if ADMA descriptor's number is enough. */
1258             entries = ((dataBytes / SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
1259             /* ADMA1 needs two descriptors to finish a transfer */
1260             entries <<= 1U;
1261             if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma1_descriptor_t)))
1262             {
1263                 error = kStatus_OutOfRange;
1264             }
1265             else
1266             {
1267                 adma1EntryAddress = (sdhc_adma1_descriptor_t *)(uint32_t)(table);
1268                 for (i = 0U; i < entries; i += 2U)
1269                 {
1270                     /* Each descriptor for ADMA1 is 32-bit in length */
1271                     if ((dataBytes - ((uint32_t)startAddress - (uint32_t)data)) <=
1272                         SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1273                     {
1274                         /* The last piece of data, setting end flag in descriptor */
1275                         adma1EntryAddress[i] = ((uint32_t)(dataBytes - ((uint32_t)startAddress - (uint32_t)data))
1276                                                 << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
1277                         adma1EntryAddress[i] |= (uint32_t)kSDHC_Adma1DescriptorTypeSetLength;
1278                         adma1EntryAddress[i + 1U] = (uint32_t)(startAddress);
1279                         adma1EntryAddress[i + 1U] |=
1280                             ((uint32_t)kSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kSDHC_Adma1DescriptorEndFlag);
1281                     }
1282                     else
1283                     {
1284                         adma1EntryAddress[i] = ((uint32_t)SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY
1285                                                 << SDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
1286                         adma1EntryAddress[i] |= (uint32_t)kSDHC_Adma1DescriptorTypeSetLength;
1287                         adma1EntryAddress[i + 1U] = ((uint32_t)(startAddress));
1288                         adma1EntryAddress[i + 1U] |= (uint32_t)kSDHC_Adma1DescriptorTypeTransfer;
1289                         startAddress += SDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t);
1290                     }
1291                 }
1292 
1293                 /* When use ADMA, disable simple DMA */
1294                 base->DSADDR  = 0U;
1295                 base->ADSADDR = (uint32_t)table;
1296             }
1297         }
1298         else
1299 #endif /* FSL_SDHC_ENABLE_ADMA1 */
1300             if (dmaMode == kSDHC_DmaModeAdma2)
1301         {
1302             /*
1303              * Add non aligned access support ,user need make sure your buffer size is big
1304              * enough to hold the data,in other words,user need make sure the buffer size
1305              * is 4 byte aligned
1306              */
1307             if (dataBytes % sizeof(uint32_t) != 0U)
1308             {
1309                 dataBytes +=
1310                     sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
1311             }
1312 
1313             /* Check if ADMA descriptor's number is enough. */
1314             entries = ((dataBytes / SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
1315             if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(sdhc_adma2_descriptor_t)))
1316             {
1317                 error = kStatus_OutOfRange;
1318             }
1319             else
1320             {
1321                 adma2EntryAddress = (sdhc_adma2_descriptor_t *)(uint32_t)(table);
1322                 for (i = 0U; i < entries; i++)
1323                 {
1324                     /* Each descriptor for ADMA2 is 64-bit in length */
1325                     if ((dataBytes - ((uint32_t)startAddress - (uint32_t)data)) <=
1326                         SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1327                     {
1328                         /* The last piece of data, setting end flag in descriptor */
1329                         adma2EntryAddress[i].address   = startAddress;
1330                         adma2EntryAddress[i].attribute = ((dataBytes - ((uint32_t)startAddress - (uint32_t)data))
1331                                                           << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
1332                         adma2EntryAddress[i].attribute |=
1333                             ((uint32_t)kSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kSDHC_Adma2DescriptorEndFlag);
1334                     }
1335                     else
1336                     {
1337                         adma2EntryAddress[i].address = startAddress;
1338                         adma2EntryAddress[i].attribute =
1339                             (((SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t)) * sizeof(uint32_t))
1340                              << SDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
1341                         adma2EntryAddress[i].attribute |= (uint32_t)kSDHC_Adma2DescriptorTypeTransfer;
1342                         startAddress += (SDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t));
1343                     }
1344                 }
1345 
1346                 /* When use ADMA, disable simple DMA */
1347                 base->DSADDR  = 0U;
1348                 base->ADSADDR = (uint32_t)table;
1349             }
1350         }
1351         else
1352         {
1353             /* Intentional empty */
1354         }
1355     }
1356 
1357     return error;
1358 }
1359 
1360 /*!
1361  * brief Transfers the command/data using a blocking method.
1362  *
1363  * This function waits until the command response/data is received or the SDHC encounters an error by polling the status
1364  * flag.
1365  * This function support non word align data addr transfer support, if data buffer addr is not align in DMA mode,
1366  * the API will continue finish the transfer by polling IO directly
1367  * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1368  * the re-entry mechanism.
1369  *
1370  * note There is no need to call the API 'SDHC_TransferCreateHandle' when calling this API.
1371  *
1372  * param base SDHC peripheral base address.
1373  * param admaTable ADMA table address, can't be null if transfer way is ADMA1/ADMA2.
1374  * param admaTableWords ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2.
1375  * param transfer Transfer content.
1376  * retval kStatus_InvalidArgument Argument is invalid.
1377  * retval kStatus_SDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1378  * retval kStatus_SDHC_SendCommandFailed Send command failed.
1379  * retval kStatus_SDHC_TransferDataFailed Transfer data failed.
1380  * retval kStatus_Success Operate successfully.
1381  */
SDHC_TransferBlocking(SDHC_Type * base,uint32_t * admaTable,uint32_t admaTableWords,sdhc_transfer_t * transfer)1382 status_t SDHC_TransferBlocking(SDHC_Type *base, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
1383 {
1384     assert(transfer != NULL);
1385 
1386     status_t error = kStatus_Success;
1387     sdhc_dma_mode_t dmaMode =
1388         (sdhc_dma_mode_t)(uint8_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
1389     sdhc_command_t *command = transfer->command;
1390     sdhc_data_t *data       = transfer->data;
1391 
1392     /* make sure the cmd/block count is valid */
1393     if ((command == NULL) || ((data != NULL) && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
1394     {
1395         return kStatus_InvalidArgument;
1396     }
1397 
1398     /* Wait until command/data bus out of busy status. */
1399     while (IS_SDHC_FLAG_SET(SDHC_GetPresentStatusFlags(base), kSDHC_CommandInhibitFlag))
1400     {
1401     }
1402     while ((data != NULL) && (IS_SDHC_FLAG_SET(SDHC_GetPresentStatusFlags(base), kSDHC_DataInhibitFlag)))
1403     {
1404     }
1405 
1406     /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1407     if ((data != NULL) && (NULL != admaTable))
1408     {
1409         error = SDHC_SetAdmaTableConfig(base, (sdhc_dma_mode_t)dmaMode, admaTable, admaTableWords,
1410                                         (data->rxData != NULL ? data->rxData : data->txData),
1411                                         (data->blockCount * data->blockSize));
1412         /* in this situation , we disable the DMA instead of polling transfer mode */
1413         if (error != kStatus_Success)
1414         {
1415             dmaMode = (sdhc_dma_mode_t)kSDHC_DmaModeNo;
1416         }
1417     }
1418 
1419     if (data != NULL)
1420     {
1421         SDHC_ClearInterruptStatusFlags(
1422             base,
1423             (uint32_t)(dmaMode == kSDHC_DmaModeNo ? kSDHC_DataFlag : kSDHC_DataDMAFlag) | (uint32_t)kSDHC_CommandFlag);
1424     }
1425     else
1426     {
1427         SDHC_ClearInterruptStatusFlags(base, kSDHC_CommandFlag);
1428     }
1429 
1430     /* Send command and receive data. */
1431     SDHC_StartTransfer(base, command, data, (sdhc_dma_mode_t)dmaMode);
1432 
1433     error = SDHC_SendCommandBlocking(base, command);
1434     if (kStatus_Success != error)
1435     {
1436         return error;
1437     }
1438 
1439     if (data != NULL)
1440     {
1441         error = SDHC_TransferDataBlocking((sdhc_dma_mode_t)dmaMode, base, data);
1442         if (kStatus_Success != error)
1443         {
1444             return error;
1445         }
1446     }
1447 
1448     return kStatus_Success;
1449 }
1450 
1451 /*!
1452  * brief Creates the SDHC handle.
1453  *
1454  * param base SDHC peripheral base address.
1455  * param handle SDHC handle pointer.
1456  * param callback Structure pointer to contain all callback functions.
1457  * param userData Callback function parameter.
1458  */
SDHC_TransferCreateHandle(SDHC_Type * base,sdhc_handle_t * handle,const sdhc_transfer_callback_t * callback,void * userData)1459 void SDHC_TransferCreateHandle(SDHC_Type *base,
1460                                sdhc_handle_t *handle,
1461                                const sdhc_transfer_callback_t *callback,
1462                                void *userData)
1463 {
1464     assert(handle != NULL);
1465     assert(callback != NULL);
1466 
1467     /* Zero the handle. */
1468     (void)memset(handle, 0, sizeof(*handle));
1469 
1470     /* Set the callback. */
1471     handle->callback.CardInserted     = callback->CardInserted;
1472     handle->callback.CardRemoved      = callback->CardRemoved;
1473     handle->callback.SdioInterrupt    = callback->SdioInterrupt;
1474     handle->callback.SdioBlockGap     = callback->SdioBlockGap;
1475     handle->callback.TransferComplete = callback->TransferComplete;
1476     handle->userData                  = userData;
1477 
1478     /* Save the handle in global variables to support the double weak mechanism. */
1479     s_sdhcHandle[SDHC_GetInstance(base)] = handle;
1480 
1481     /* save IRQ handler */
1482     s_sdhcIsr = SDHC_TransferHandleIRQ;
1483 
1484     (void)EnableIRQ(s_sdhcIRQ[SDHC_GetInstance(base)]);
1485 }
1486 
1487 /*!
1488  * brief Transfers the command/data using an interrupt and an asynchronous method.
1489  *
1490  * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
1491  * error.
1492  * This function support non word align data addr transfer support, if data buffer addr is not align in DMA mode,
1493  * the API will continue finish the transfer by polling IO directly
1494  * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1495  * the re-entry mechanism.
1496  *
1497  * note Call the API 'SDHC_TransferCreateHandle' when calling this API.
1498  *
1499  * param base SDHC peripheral base address.
1500  * param handle SDHC handle.
1501  * param admaTable ADMA table address, can't be null if transfer way is ADMA1/ADMA2.
1502  * param admaTableWords ADMA table length united as words, can't be 0 if transfer way is ADMA1/ADMA2.
1503  * param transfer Transfer content.
1504  * retval kStatus_InvalidArgument Argument is invalid.
1505  * retval kStatus_SDHC_BusyTransferring Busy transferring.
1506  * retval kStatus_SDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1507  * retval kStatus_Success Operate successfully.
1508  */
SDHC_TransferNonBlocking(SDHC_Type * base,sdhc_handle_t * handle,uint32_t * admaTable,uint32_t admaTableWords,sdhc_transfer_t * transfer)1509 status_t SDHC_TransferNonBlocking(
1510     SDHC_Type *base, sdhc_handle_t *handle, uint32_t *admaTable, uint32_t admaTableWords, sdhc_transfer_t *transfer)
1511 {
1512     assert(transfer != NULL);
1513 
1514     sdhc_dma_mode_t dmaMode =
1515         (sdhc_dma_mode_t)(uint8_t)((base->PROCTL & SDHC_PROCTL_DMAS_MASK) >> SDHC_PROCTL_DMAS_SHIFT);
1516     status_t error          = kStatus_Success;
1517     sdhc_command_t *command = transfer->command;
1518     sdhc_data_t *data       = transfer->data;
1519 
1520     /* make sure cmd/block count is valid */
1521     if ((command == NULL) || ((data != NULL) && (data->blockCount > SDHC_MAX_BLOCK_COUNT)))
1522     {
1523         return kStatus_InvalidArgument;
1524     }
1525 
1526     /* Wait until command/data bus out of busy status. */
1527     if ((IS_SDHC_FLAG_SET(SDHC_GetPresentStatusFlags(base), kSDHC_CommandInhibitFlag)) ||
1528         ((data != NULL) && (IS_SDHC_FLAG_SET(SDHC_GetPresentStatusFlags(base), kSDHC_DataInhibitFlag))))
1529     {
1530         return kStatus_SDHC_BusyTransferring;
1531     }
1532 
1533     /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1534     if ((data != NULL) && (NULL != admaTable))
1535     {
1536         error = SDHC_SetAdmaTableConfig(base, dmaMode, admaTable, admaTableWords,
1537                                         (data->rxData != NULL ? data->rxData : data->txData),
1538                                         (data->blockCount * data->blockSize));
1539         /* in this situation , we disable the DMA instead of polling transfer mode */
1540         if (error != kStatus_Success)
1541         {
1542             /* change to polling mode */
1543             dmaMode = kSDHC_DmaModeNo;
1544         }
1545     }
1546 
1547     /* Save command and data into handle before transferring. */
1548     handle->command = command;
1549     handle->data    = data;
1550     /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1551     handle->transferredWords = 0U;
1552 
1553     /* enable interrupt per transfer request */
1554     if (handle->data != NULL)
1555     {
1556         SDHC_ClearInterruptStatusFlags(
1557             base,
1558             (uint32_t)(dmaMode == kSDHC_DmaModeNo ? kSDHC_DataFlag : kSDHC_DataDMAFlag) | (uint32_t)kSDHC_CommandFlag);
1559         SDHC_EnableInterruptSignal(base, (uint32_t)(dmaMode == kSDHC_DmaModeNo ? kSDHC_DataFlag : kSDHC_DataDMAFlag) |
1560                                              (uint32_t)kSDHC_CommandFlag);
1561     }
1562     else
1563     {
1564         SDHC_ClearInterruptStatusFlags(base, kSDHC_CommandFlag);
1565         SDHC_EnableInterruptSignal(base, kSDHC_CommandFlag);
1566     }
1567 
1568     SDHC_StartTransfer(base, command, data, dmaMode);
1569 
1570     return kStatus_Success;
1571 }
1572 
1573 /*!
1574  * brief IRQ handler for the SDHC.
1575  *
1576  * This function deals with the IRQs on the given host controller.
1577  *
1578  * param base SDHC peripheral base address.
1579  * param handle SDHC handle.
1580  */
SDHC_TransferHandleIRQ(SDHC_Type * base,sdhc_handle_t * handle)1581 void SDHC_TransferHandleIRQ(SDHC_Type *base, sdhc_handle_t *handle)
1582 {
1583     assert(handle != NULL);
1584 
1585     uint32_t interruptFlags;
1586 
1587     interruptFlags = SDHC_GetEnabledInterruptStatusFlags(base);
1588 
1589     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_CardDetectFlag))
1590     {
1591         SDHC_TransferHandleCardDetect(base, handle, interruptFlags);
1592     }
1593     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_CommandFlag))
1594     {
1595         SDHC_TransferHandleCommand(base, handle, interruptFlags);
1596     }
1597     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_DataFlag))
1598     {
1599         SDHC_TransferHandleData(base, handle, interruptFlags);
1600     }
1601     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_CardInterruptFlag))
1602     {
1603         SDHC_TransferHandleSdioInterrupt(base, handle);
1604     }
1605     if (IS_SDHC_FLAG_SET(interruptFlags, kSDHC_BlockGapEventFlag))
1606     {
1607         SDHC_TransferHandleSdioBlockGap(base, handle);
1608     }
1609 
1610     SDHC_ClearInterruptStatusFlags(base, interruptFlags);
1611 }
1612 
1613 #if defined(SDHC)
1614 void SDHC_DriverIRQHandler(void);
SDHC_DriverIRQHandler(void)1615 void SDHC_DriverIRQHandler(void)
1616 {
1617     assert(s_sdhcHandle[0] != NULL);
1618 
1619     s_sdhcIsr(SDHC, s_sdhcHandle[0]);
1620     SDK_ISR_EXIT_BARRIER;
1621 }
1622 #endif
1623