]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/arm/mxc/v2_0/src/mxcmci_sd.c
TX51/TX53 Release 2011-08-19
[karo-tx-redboot.git] / packages / devs / flash / arm / mxc / v2_0 / src / mxcmci_sd.c
1 // ==========================================================================
2 //
3 //   mxcmci_sd.c
4 //   (c) 2008, Freescale
5 //
6 //   MMC card driver for MXC platform
7 //
8 // ==========================================================================
9 //####ECOSGPLCOPYRIGHTBEGIN####
10 // -------------------------------------------
11 // This file is part of eCos, the Embedded Configurable Operating System.
12 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    Lewis Liu <weizhi.liu@freescale.com>
45 // Contributors: Lewis Liu <weizhi.liu@freescale.com>
46 // Date:         2008-05-13 Initial version
47 // Purpose:
48 // Description:
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <cyg/infra/diag.h>
55 #include <cyg/io/mxcmci_host.h>
56 #include <cyg/io/mxcmci_core.h>
57 #include <cyg/io/mxcmci_mmc.h>
58
59 static cyg_uint32 sd_get_rca(void);
60 static cyg_uint32 sd_get_bit_mode_support(void);
61 static cyg_uint32 sd_set_bus_width(cyg_uint32);
62 static cyg_uint32 sd_set_high_speed_mode(void);
63
64 #define SD_OCR_VALUE_HV_LC 0x00ff8000    /* nirp_oct07: <- 3.3v, LC */
65 #define SD_OCR_VALUE_HV_HC 0x40ff8000    /* nirp_oct07: <- 3.3v, HC */
66 /* nirp_oct07: LV_LC not needed - 1.8v is only supported under eSD which supports HC by default (SD>2.00) */
67 #define SD_OCR_VALUE_LV_HC 0x40000080    /* nirp_oct07: <- 1.8v, HC */
68
69 #define SD_OCR_HC_RES 0x40000000
70 #define SD_OCR_LC_RES 0x00000000
71
72 #define SD_IF_HV_COND_ARG 0x000001AA
73 #define SD_IF_LV_COND_ARG 0x000002AA
74
75 #define RCA_SHIFT 16
76 #define SD_R1_STATUS_APP_CMD_MSK 0x20
77 #define BIT_MODE_4_SUPPORT 5
78 #define SD_BUS_WIDTH_OFFSET 6
79 #define BIT_4_MODE 4
80 #define SD_STATUS_LEN 64
81
82 #define SD_BOOT_SWITCH_ARG 0x80FFFF2F
83 #define SD_PARTITION1 0x01000000
84
85 cyg_uint32 sd_init(cyg_uint32 bus_width)
86 {
87         cyg_uint32 status = FAIL;
88         cyg_uint32 bus_size = bus_width;
89
90         /* Get CID number of SD Memory Card */
91         if (!mxcmci_get_cid()) {
92                 //diag_printf("%s:mxcmci_get_cid OK!\n", __FUNCTION__);
93                 /* Set RCA of the SD Card */
94                 if (!sd_get_rca()) {
95                         //diag_printf("%s:sd_get_rca OK!\n", __FUNCTION__);
96                         /*Get CSD from Card */
97                         if (card_get_csd())
98                                 return FAIL;
99
100                         /*Enable operating frequency */
101                         host_cfg_clock(OPERATING_FREQ);
102
103                         //diag_printf("Set SD Card in Transfer State.\n");
104
105                         /*Put SD Card in Transfer State */
106                         if (!mxcmci_trans_prepare()) {
107 #if 0
108                                 if (sd_set_high_speed_mode()) {
109                                         return FAIL;
110                                 }
111 #endif
112
113                                 if (sdmmc_set_blklen(BLK_LEN))
114                                         return FAIL;
115
116                                 /* SD can only support 1/4 bit bitwidth, 8 bit is not supported */
117                                 if (8 == bus_width) {
118                                         bus_width = 4;
119                                 }
120                                 if (!sd_set_bus_width(bus_width)) {
121                                         esdhc_base_pointer->protocol_control &=
122                                                 ~(0x3 << 1);
123                                         esdhc_base_pointer->protocol_control |=
124                                                 (bus_width / 4) << 1;
125                                         diag_printf("Bus Width:    %d\n",
126                                                                 bus_width);
127                                         status = SUCCESS;
128                                 }
129                         }
130                 }
131
132         } else {
133                 diag_printf("Get CID Failed.\n");
134
135         }
136
137         //diag_printf("%s:failed to Init SD card!\n", __FUNCTION__);
138         return status;
139
140 }
141
142 cyg_uint32 sd_voltage_validation(void)
143 {
144         //wait max timeout (unit: ms)
145         cyg_uint32 timeout = 15000;
146
147         command_t cmd;
148         command_response_t response;
149         cyg_uint32 voltage_validation_command = 0;
150         cyg_uint32 default_rca = 0;
151
152         cyg_uint32 ocr_value = SD_OCR_VALUE_HV_LC;    /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
153         cyg_uint32 voltage_validation = FAIL;
154         cyg_uint32 interface_value = 0;
155         cyg_uint32 card_usable = SUCCESS;
156
157         /* Configure Command CMD8 to check for High capacity support */
158         /* try 3.3V first */
159         mxcmci_cmd_config(&cmd, CMD8, SD_IF_HV_COND_ARG, READ, RESPONSE_48,
160                                         DATA_PRESENT_NONE, ENABLE, ENABLE);
161
162         /* Issue Command CMD8  to SD Memory card */
163         if (host_send_cmd(&cmd) == SUCCESS) {    /* nirp_oct07: <- changed order of detection */
164                 //diag_printf("%s:CMD8 OK!\n", __FUNCTION__);
165                 response.format = RESPONSE_48;
166                 host_read_response(&response);
167
168                 /* Obtain Interface value from the response buffer */
169                 interface_value = response.cmd_rsp0;
170
171                 /* Check if volatge lies in range or not */
172                 if ((interface_value & SD_IF_HV_COND_ARG) == SD_IF_HV_COND_ARG) {
173                         ocr_value = ((cyg_uint32) (SD_OCR_VALUE_HV_HC) & 0xFFFFFFFF);    /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
174                 }
175
176                 /* start timer for a  delay of 1.5sec, for ACMD41 */
177                 hal_delay_us(1500);
178
179                 while ((voltage_validation_command < 20)
180                         && (voltage_validation != SUCCESS)
181                         && (card_usable == SUCCESS)) {
182                         /* Configure CMD55 for SD card */
183                         /* This command expects defualt RCA 0x0000 as argument. */
184                         mxcmci_cmd_config(&cmd, CMD55, default_rca, READ,
185                                                         RESPONSE_48, DATA_PRESENT_NONE,
186                                                         ENABLE, ENABLE);
187
188                         /* Issue CMD55 to SD Memory card */
189                         if (host_send_cmd(&cmd) == FAIL) {
190                                 voltage_validation = FAIL;
191                                 //diag_printf("Send CMD55 Failed.\n");
192                                 break;
193                         } else {
194                                 /* Configure ACMD41 for SD card */
195                                 /* This command expects operating voltage range as argument. */
196                                 /* CODE REVIEW START: Need to check why BUSY was expected */
197                                 /* INTERNAL CODE REVIEW: Accepted - to fix original code if needed */
198                                 /* nirp: changed RESPONSE_48_CHECK_BUSY to RESPONSE_48 */
199                                 /* nirp_oct03: why with busy again? ACMD41 doesn't hold busy line */
200                                 mxcmci_cmd_config(&cmd, ACMD41, ocr_value, READ,
201                                                                 RESPONSE_48, DATA_PRESENT_NONE, DISABLE,
202                                                                 DISABLE);
203
204                                 /* Issue ACMD41 to SD Memory card to determine OCR value */
205                                 if (host_send_cmd(&cmd) == FAIL) {
206                                         voltage_validation = FAIL;
207                                         diag_printf("Send CMD41 Failed.\n");
208                                         break;
209                                 } else {
210                                         /* Read Response from CMDRSP0 Register */
211                                         response.format = RESPONSE_48;
212                                         host_read_response(&response);
213
214                                         /* Obtain OCR Values from the response */
215                                         /* Obtain OCR value from the response buffer */
216                                         ocr_value = response.cmd_rsp0;
217
218                                         /* Check if card busy bit is cleared or not */
219                                         if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
220                                                 /* Iterate One more time */
221                                                 voltage_validation_command++;
222                                         } else {
223
224                                                 /*CODE REVIEW START: Update code and check only bit 30, HC or LC card type. All voltage bits needs to be masked. */
225                                                 /* INTERNAL CODE REVIEW: Accepted - need fix the code accordingly */
226                                                 /* nirp: It may be better to check the actual power supply voltage - requiring the entire range (0xff8000) may fail the sequence even if the device can be supported */
227                                                 /*CODE REVIEW END: */
228
229                                                 if ((response.cmd_rsp0 & SD_OCR_HC_RES) == SD_OCR_HC_RES) {
230                                                         address_mode = SECT_MODE;
231                                                         voltage_validation = SUCCESS;
232                                                 }
233                                                 /* CODE REVIEW 3: (same as above) Check is logically correct, but seems redundent.
234                                                    Anything that fails the HC check, is assumed Low Capacity */
235                                                 /* nirp_oct03: this can be just an "else". the LC macro is 0 anyway,
236                                                    and anything not HC is LC by default */
237                                                 /* removed else if */
238                                                 else {
239                                                         address_mode = BYTE_MODE;
240                                                         voltage_validation = SUCCESS;
241                                                 }
242                                         }
243                                 }
244                         }
245
246                         hal_delay_us(1000);
247                 }
248
249                 if (voltage_validation == FAIL) {
250                         card_usable = FAIL;
251                 }
252
253         } else {
254                 /*3.3v test failed, try to test 1.8v mode! */
255                 mxcmci_cmd_config(&cmd, CMD8, SD_IF_LV_COND_ARG, READ,
256                                                 RESPONSE_48, DATA_PRESENT_NONE, ENABLE,
257                                                 ENABLE);
258
259                 /* Issue Command CMD8  to SD Memory card */
260                 if (host_send_cmd(&cmd) == FAIL) {
261                         //diag_printf("%s:CMD8 for 1.8v failed!\n", __FUNCTION__);
262                         /* nirp_oct07: CMD8 failed both in 3.3 and in 1.8v, try SD 1.x case - no CMD8, LC, 3.3v only */
263                         ocr_value = ((cyg_uint32) (SD_OCR_VALUE_HV_LC) & 0xFFFFFFFF);    /* nirp_oct07: <- changed order of detection */
264                 } else {
265                         //diag_printf("%s:CMD8 for 1.8v OK!\n", __FUNCTION__);
266                         response.format = RESPONSE_48;
267                         host_read_response(&response);
268
269                         /* Obtain Interface value from the response buffer */
270                         interface_value = response.cmd_rsp0;
271
272                         /* Check if volatge lies in range or not */
273                         if ((interface_value & SD_IF_LV_COND_ARG) == SD_IF_LV_COND_ARG) {
274                                 ocr_value = ((cyg_uint32) (SD_OCR_VALUE_LV_HC) & 0xFFFFFFFF);    /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
275                         }
276                         /* nirp_oct07: otherwise, try with HV_LC settings (set at function start) */
277                 }
278
279         }
280
281         /* start timer for a  delay of 1.5sec, for ACMD41 */
282         hal_delay_us(1500);
283
284         /* nirp_oct03: MMCSD_READY_TIMEOUT too long.
285            ACMD41 also takes longer than CMD1 (twice - ~200 clocks for CMD55+resp+CMD41+resp */
286         /* In any case ,ACMD 41 will loop not more than 1.5 sec */
287         while ((voltage_validation_command < 20)
288                 && (voltage_validation != SUCCESS) && (card_usable == SUCCESS)) {
289                 /* Configure CMD55 for SD card */
290                 /* This command expects defualt RCA 0x0000 as argument. */
291                 mxcmci_cmd_config(&cmd, CMD55, default_rca, READ, RESPONSE_48,
292                                                 DATA_PRESENT_NONE, ENABLE, ENABLE);
293
294                 /* Issue CMD55 to SD Memory card */
295                 if (host_send_cmd(&cmd) == FAIL) {
296                         voltage_validation = FAIL;
297                         //diag_printf("Send CMD55 Failed!\n");
298                         break;
299                 } else {
300                         /* Configure ACMD41 for SD card */
301                         /* This command expects operating voltage range as argument. */
302                         /* CODE REVIEW START: Need to check why BUSY was expected */
303                         /* INTERNAL CODE REVIEW: Accepted - to fix original code if needed */
304                         /* nirp: changed RESPONSE_48_CHECK_BUSY to RESPONSE_48 */
305                         /* nirp_oct03: why with busy again? ACMD41 doesn't hold busy line */
306                         mxcmci_cmd_config(&cmd, ACMD41, ocr_value, READ,
307                                                         RESPONSE_48, DATA_PRESENT_NONE,
308                                                         DISABLE, DISABLE);
309
310                         /* CODE REVIEW END:  */
311
312                         /* Issue ACMD41 to SD Memory card to determine OCR value */
313                         if (host_send_cmd(&cmd) == FAIL) {
314                                 voltage_validation = FAIL;
315                                 diag_printf("Send ACMD41 Failed!\n");
316                                 break;
317                         } else {
318                                 /* Read Response from CMDRSP0 Register */
319                                 response.format = RESPONSE_48;
320                                 host_read_response(&response);
321
322                                 /* Obtain OCR Values from the response */
323                                 /* Obtain OCR value from the response buffer
324                                  */
325                                 ocr_value = response.cmd_rsp0;
326
327                                 /* Check if card busy bit is cleared or not */
328                                 if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
329                                         /* Iterate One more time */
330                                         voltage_validation_command++;
331                                 } else {
332                                         /*CODE REVIEW START: Update code and check only bit 30, HC or LC card type. All voltage bits needs to be masked. */
333                                         /* INTERNAL CODE REVIEW: Accepted - need fix the code accordingly */
334                                         /* nirp: It may be better to check the actual power supply voltage - requiring the entire range (0xff8000) may fail the sequence even if the device can be supported */
335                                         /*CODE REVIEW END: */
336
337                                         if ((response.cmd_rsp0 & SD_OCR_HC_RES) == SD_OCR_HC_RES) {
338                                                 address_mode = SECT_MODE;
339                                                 voltage_validation = SUCCESS;
340                                         }
341                                         /* CODE REVIEW 3: (same as above) Check is logically correct, but seems redundent.
342                                            Anything that fails the HC check, is assumed Low Capacity */
343                                         /* nirp_oct03: this can be just an "else". the LC macro is 0 anyway,
344                                            and anything not HC is LC by default */
345                                         else {
346                                                 address_mode = BYTE_MODE;
347                                                 voltage_validation = SUCCESS;
348                                         }
349                                 }
350                         }
351
352                 }
353
354                 hal_delay_us(1000);
355
356         }
357
358         return voltage_validation;
359 }
360
361 static cyg_uint32 sd_get_rca(void)
362 {
363         command_t cmd;
364         cyg_uint32 card_state = 0;
365         cyg_uint32 rca_request = 0;
366         command_response_t response;
367
368         /* Configure CMD3 for MMC card */
369         /* 32bit card address is expected as Argument */
370         mxcmci_cmd_config(&cmd, CMD3, NO_ARG, READ, RESPONSE_48,
371                                         DATA_PRESENT_NONE, ENABLE, ENABLE);
372
373         /* Get relative address of the card     */
374
375         if (host_send_cmd(&cmd) == FAIL) {
376                 rca_request = FAIL;
377                 diag_printf("Send CMD3 Failed.\n");
378         } else {
379                 /* Read Command response */
380                 response.format = RESPONSE_48;
381                 host_read_response(&response);
382
383                 Card_rca = ((cyg_uint32) (response.cmd_rsp0 >> RCA_SHIFT));
384
385                 card_state = CURR_CARD_STATE(response.cmd_rsp0);
386
387                 if (card_state == IDENT) {
388                         rca_request = SUCCESS;
389                 } else {
390                         rca_request = FAIL;
391                         diag_printf("Get RCA Failed.\n");
392                 }
393         }
394
395         return rca_request;
396 }
397
398 static cyg_uint32 sd_get_bit_mode_support(void)
399 {
400         command_t cmd;
401         cyg_uint32 rd_data_buff[128];
402         cyg_uint32 bit4_mode_support;
403         command_response_t response;
404         cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
405
406         /* Configure CMD55 for SD card */
407         /* This command expects RCA as argument. */
408         mxcmci_cmd_config(&cmd, CMD55, card_address, READ, RESPONSE_48,
409                                         DATA_PRESENT_NONE, ENABLE, ENABLE);
410
411         /* Issue CMD55 to SD Memory card */
412         if (host_send_cmd(&cmd) == FAIL) {
413                 bit4_mode_support = 0;
414         } else {
415                 /* Read Command response */
416                 response.format = RESPONSE_48;
417                 host_read_response(&response);
418
419                 /* Afetr giving ACMD Command, the R1 response should have
420                  * STATUS_APP_CMD set
421                  */
422                 if (response.cmd_rsp0 & SD_R1_STATUS_APP_CMD_MSK) {
423
424                         /* Configure ACMD51 for SD card */
425                         /* This command expects No argument. */
426
427                         mxcmci_cmd_config(&cmd, ACMD51, NO_ARG, READ,
428                                                         RESPONSE_48, DATA_PRESENT, ENABLE,
429                                                         ENABLE);
430
431                         /* Issue ACMD51 to SD Memory card */
432                         if (host_send_cmd(&cmd) == FAIL) {
433                                 bit4_mode_support = 0;
434                         } else {
435                                 /* Read Response from e-SDHC buffer */
436                                 host_data_read(rd_data_buff, 512);
437
438                                 /* Check for bus width supported */
439                                 bit4_mode_support = (rd_data_buff[SD_BUS_WIDTH_OFFSET] & BIT_MODE_4_SUPPORT);
440
441                                 if (bit4_mode_support) {
442                                         bit4_mode_support = BIT_4_MODE;
443                                 }
444
445                         }
446                 }
447         }
448
449         return bit4_mode_support;
450 }
451
452 static cyg_uint32 sd_set_bus_width(cyg_uint32 bus_width)
453 {
454         command_t cmd;
455         cyg_uint32 set_bus_width_status = 0;
456         command_response_t response;
457         cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
458
459         if ((bus_width == 4) || (bus_width == 1)) {
460                 /* Configure CMD55 for SD card */
461                 /* This command expects RCA as argument. */
462
463                 mxcmci_cmd_config(&cmd, CMD55, card_address, READ, RESPONSE_48,
464                                                 DATA_PRESENT_NONE, ENABLE, ENABLE);
465
466                 /* Issue CMD55 to SD Memory card */
467                 if (host_send_cmd(&cmd) == FAIL) {
468                         set_bus_width_status = FAIL;
469                 } else {
470                         /* Read Command response */
471                         response.format = RESPONSE_48;
472                         host_read_response(&response);
473
474                         /* Afetr giving ACMD Command, the R1 response should have
475                          * STATUS_APP_CMD set
476                          */
477                         if (response.cmd_rsp0 & SD_R1_STATUS_APP_CMD_MSK) {
478                                 bus_width = (bus_width >> ONE);
479
480                                 /* Configure ACMD6 for SD card */
481                                 mxcmci_cmd_config(&cmd, ACMD6, bus_width, READ,
482                                                                 RESPONSE_48,
483                                                                 DATA_PRESENT_NONE, ENABLE,
484                                                                 ENABLE);
485
486                                 /* Issue ACMD6 to SD Memory card */
487                                 if (host_send_cmd(&cmd) == FAIL) {
488                                         set_bus_width_status = FAIL;
489                                 } else {
490                                         set_bus_width_status = SUCCESS;
491                                 }
492                         }
493                 }
494         }
495
496         return set_bus_width_status;
497 }
498
499 /*==========================================================================
500 FUNCTION: cyg_uint32 sd_set_boot_partition (void)
501 DESCRIPTION:
502   sd_set_boot_partition() will set set boot partition for Partition1
503
504 RETURN VALUE:
505    SUCCESS / FAILURE
506
507 PRE-CONDITIONS:
508    None
509
510 POST-CONDITIONS:
511    None
512
513 Detailed Description:
514
515 ==============================================================================*/
516
517 cyg_uint32 esd_set_boot_partition(cyg_uint32 *src_ptr, cyg_uint32 length)
518 {
519         command_t cmd;
520         cyg_uint32 set_partition_status = FAIL;
521         command_response_t response;
522         cyg_uint8 response_data[512];
523         cyg_uint32 *response_pointer = (cyg_uint32 *) response_data;
524         cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
525         cyg_uint32 card_state;
526
527         /* Send CMD43 to select partition PARTITION1 active */
528         mxcmci_cmd_config(&cmd, CMD43,
529                                         0x1<<24,
530                                         READ,
531                                         RESPONSE_48,
532                                         DATA_PRESENT_NONE,
533                                         ENABLE,
534                                         ENABLE);
535
536         if(host_send_cmd(&cmd) == FAIL) {
537                 //diag_printf("%s: Send CMD43 Failed.\n", __FUNCTION__);
538                 return 1;
539         }
540
541         set_partition_status = mmc_data_write (src_ptr, length, 0);
542         if(set_partition_status) {
543                 return 1; /* failed */
544         }
545
546         return 0;
547 }
548
549 static cyg_uint32 sd_set_high_speed_mode(void)
550 {
551         command_t cmd;
552         cyg_uint32 status = FAIL;
553         command_response_t response;
554
555         /* Configure CMD6 for SD card */
556         mxcmci_cmd_config(&cmd, CMD6, 0xfffff1, READ, RESPONSE_48,
557                                         DATA_PRESENT_NONE, ENABLE, ENABLE);
558
559         /* Issue CMD6 to SD Memory card */
560         if (host_send_cmd(&cmd) == FAIL) {
561                 status = FAIL;
562                 diag_printf("Send CMD6 Failed.\n");
563                 return FAIL;
564         } else {
565                 hal_delay_us(1000);
566                 status = SUCCESS;
567
568         }
569
570         mxcmci_cmd_config(&cmd, CMD6, 0x80fffff1, READ, RESPONSE_48,
571                                         DATA_PRESENT_NONE, ENABLE, ENABLE);
572
573         /* Issue CMD6 to SD Memory card */
574         if (host_send_cmd(&cmd) == FAIL) {
575                 status = FAIL;
576                 diag_printf("Send CMD6 Failed.\n");
577         } else {
578                 /* wait until in transfer mode */
579                 while (mxcmci_trans_status()) {
580                         hal_delay_us(5);
581                 }
582
583                 status = SUCCESS;
584         }
585
586         return status;
587 }
588
589 /* end of mxcmic_sd.c */