LPCOpen Platform for LPC18XX/43XX microcontrollers: C:/w/lpcopen_docs/software/lpc_core/lpc_chip/chip_18xx_43xx/sdio_18xx_43xx.c Source File

| LPCOpen Platform for LPC18XX/43XX microcontrollers 18XX43XX LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

sdio_18xx_43xx.c
Go to the documentation of this file.
1 /*
2 * @brief LPC18xx/43xx SDIO Card driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include "chip.h"
33
34 /*****************************************************************************
35 * Private types/enumerations/variables
36 ****************************************************************************/
37
38 #define SDIO_CMD_INT_MSK 0xA146 /* Interrupts to be enabled for CMD */
39 #define SDIO_DATA_INT_MSK 0xBE88 /* Interrupts to enable for data transfer */
40 #define SDIO_CARD_INT_MSK (1UL << 16) /* SDIO Card interrupt */
41
42 static struct
43 {
44 void (*wake_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg);
45 uint32_t (*wait_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg);
46 uint32_t flag;
47 uint32_t response[4];
48 int fnum;
49 uint16_t blkSz[8]; /* Block size setting for the 8- function blocks */
50 sdif_device sdev; /* SDIO interface device structure */
51 }sdio_context, *sdioif = &sdio_context;
52
53 /*****************************************************************************
54 * Public types/enumerations/variables
55 ****************************************************************************/
56
57 /*****************************************************************************
58 * Private functions
59 ****************************************************************************/
60
61 /* Set the SDIO Card voltage level to 3v3 */
62 static int SDIO_Card_SetVoltage(LPC_SDMMC_T *pSDMMC)
63 {
64 int ret, i;
65 uint32_t val;
66
67 ret = SDIO_Send_Command(pSDMMC, CMD5, 0);
68 if (ret) return ret;
69 val = sdioif->response[0];
70
71 /* Number of functions supported by the card */
72 sdioif->fnum = (val >> 28) & 7;
73
74 /* Check number of I/O functions*/
75 if(sdioif->fnum == 0) {
76 /* Number of I/O functions */
77 return SDIO_ERR_FNUM;
78 }
79
80 /* ---- check OCR ---- */
81 if((val & SDIO_VOLT_3_3) == 0){
82 /* invalid voltage */
83 return SDIO_ERR_VOLT;
84 }
85
86 /* ==== send CMD5 write new voltage === */
87 for(i = 0; i < 100; i++){
88 ret = SDIO_Send_Command(pSDMMC, CMD5, SDIO_VOLT_3_3);
89 if (ret) return ret;
90 val = sdioif->response[0];
91
92 /* Is card ready ? */
93 if(val & (1UL << 31)){
94 break;
95 }
96
97 sdioif->wait_evt(pSDMMC, SDIO_WAIT_DELAY, (void *)10);
98 }
99
100 /* ==== Check C bit ==== */
101 if(val & (1UL << 31)){
102 return 0;
103 }
104
105 return SDIO_ERR_VOLT; /* error end */
106 }
107
108 /* Set SDIO Card RCA */
109 static int SDIO_CARD_SetRCA(LPC_SDMMC_T *pSDMMC)
110 {
111 int ret;
112
113 /* ==== send CMD3 get RCA ==== */
114 ret = SDIO_Send_Command(pSDMMC, CMD3, 0);
115 if (ret) return ret;
116
117 /* R6 response to CMD3 */
118 if((sdioif->response[0] & 0x0000e000) != 0){
119 /* COM_CRC_ERROR */
120 /* ILLEGAL_CRC_ERROR */
121 /* ERROR */
122 return SDIO_ERR_RCA;
123 }
124
125 /* change card state */
126 sdioif->flag |= SDIO_POWER_INIT;
127
128 /* New published RCA */
129 sdioif->response[0] &= 0xffff0000;
130
131 /* ==== change state to Stanby State ==== */
132 return SDIO_Send_Command(pSDMMC, CMD7, sdioif->response[0]);
133 }
134
135 /* Set the Clock speed and mode [1/4 bit] of the card */
136 static int SDIO_Card_SetMode(LPC_SDMMC_T *pSDMMC, uint32_t clk, int mode_4bit)
137 {
138 int ret;
139 uint32_t val;
140
141 Chip_SDIF_SetClock(pSDMMC, Chip_Clock_GetBaseClocktHz(CLK_BASE_SDIO), clk);
142
143 if (!mode_4bit)
144 return 0;
145
146 val = 0x02;
147 ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, 0x07, &val);
148 if (ret) return ret;
149
150 if (val & 0x02) {
151 Chip_SDIF_SetCardType(pSDMMC, MCI_CTYPE_4BIT);
152 }
153 return 0;
154 }
155
156 /*****************************************************************************
157 * Public functions
158 ****************************************************************************/
159 /* Set the block size of a function */
160 int SDIO_Card_SetBlockSize(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t blkSize)
161 {
162 int ret;
163 uint32_t tmp, asz;
164 if (func > sdioif->fnum)
165 return SDIO_ERR_INVFUNC;
166
167 if (blkSize > 2048)
168 return SDIO_ERR_INVARG;
169
170 tmp = blkSize & 0xFF;
171 ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, (func << 8) + 0x10, &tmp);
172 if (ret) return ret;
173 asz = tmp;
174
175 tmp = blkSize >> 8;
176 ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, (func << 8) + 0x11, &tmp);
177 if (ret) return ret;
178 asz |= tmp << 8;
179 sdioif->blkSz[func] = asz;
180 return 0;
181 }
182
183 /* Get the block size of a particular function */
184 uint32_t SDIO_Card_GetBlockSize(LPC_SDMMC_T *pSDMMC, uint32_t func)
185 {
186 if (func > sdioif->fnum)
187 return 0;
188
189 return sdioif->blkSz[func];
190 }
191
192 /* Write data to SDIO Card */
193 int SDIO_Card_WriteData(LPC_SDMMC_T *pSDMMC, uint32_t func,
194 uint32_t dest_addr, const uint8_t *src_addr,
195 uint32_t size, uint32_t flags)
196 {
197 int ret;
198 uint32_t bs = size, bsize = size;
199 uint32_t cmd = CMD53 | (1UL << 10);
200
201 if (func > sdioif->fnum)
202 return SDIO_ERR_INVFUNC;
203
204 if (bsize > 512 || bsize == 0)
205 return SDIO_ERR_INVARG;
206
207 if (flags & SDIO_MODE_BLOCK) {
208 uint32_t bs = SDIO_Card_GetBlockSize(pSDMMC, func);
209 if (!bs) return SDIO_ERR_INVARG;
210 size *= bs;
211 }
212
213 /* Set Block Size */
214 Chip_SDIF_SetBlkSize(pSDMMC, bs);
215
216 /* set number of bytes to read */
217 Chip_SDIF_SetByteCnt(pSDMMC, size);
218
219 sdioif->wait_evt(pSDMMC, SDIO_START_DATA, 0);
220 Chip_SDIF_DmaSetup(pSDMMC, &sdioif->sdev, (uint32_t) src_addr, size);
221
222 ret = SDIO_Send_Command(pSDMMC, cmd, (func << 28) | (dest_addr << 9) | (bsize & 0x1FF) | (1UL << 31) | (flags & (0x3 << 26)));
223 if (ret) return ret;
224
225 /* Check response for errors */
226 if(sdioif->response[0] & 0xcb00){
227 /* COM_CRC_ERROR */
228 /* ILLEGAL_CRC_ERROR */
229 /* ERROR */
230 /* RFU FUNCTION_NUMBER */
231 /* OUT_OF_RANGE */
232 /* Response flag error */
233 return SDIO_ERR_READWRITE;
234 }
235 return sdioif->wait_evt(pSDMMC, SDIO_WAIT_DATA, 0);
236 }
237
238 /* Write data to SDIO Card */
239 int SDIO_Card_ReadData(LPC_SDMMC_T *pSDMMC, uint32_t func, uint8_t *dest_addr, uint32_t src_addr, uint32_t size, uint32_t flags)
240 {
241 int ret;
242 uint32_t bs = size, bsize = size;
243 uint32_t cmd = CMD53;
244
245 if (func > sdioif->fnum)
246 return SDIO_ERR_INVFUNC;
247
248 if (bsize > 512 || bsize == 0)
249 return SDIO_ERR_INVARG;
250
251 if (flags & SDIO_MODE_BLOCK) {
252 bs = SDIO_Card_GetBlockSize(pSDMMC, func);
253 if (!bs) return SDIO_ERR_INVARG;
254 size *= bs;
255 }
256 /* Set the block size */
257 Chip_SDIF_SetBlkSize(pSDMMC, bs);
258
259 /* set number of bytes to read */
260 Chip_SDIF_SetByteCnt(pSDMMC, size);
261
262 sdioif->wait_evt(pSDMMC, SDIO_START_DATA, 0);
263 Chip_SDIF_DmaSetup(pSDMMC, &sdioif->sdev, (uint32_t) dest_addr, size);
264
265 ret = SDIO_Send_Command(pSDMMC, cmd | (1 << 13), (func << 28) | (src_addr << 9) | (bsize & 0x1FF) | (flags & (0x3 << 26)));
266 if (ret) return ret;
267
268 /* Check response for errors */
269 if(sdioif->response[0] & 0xcb00){
270 /* COM_CRC_ERROR */
271 /* ILLEGAL_CRC_ERROR */
272 /* ERROR */
273 /* RFU FUNCTION_NUMBER */
274 /* OUT_OF_RANGE */
275 /* Response flag error */
276 return SDIO_ERR_READWRITE;
277 }
278
279 return sdioif->wait_evt(pSDMMC, SDIO_WAIT_DATA, 0);
280 }
281
282 /* Enable SDIO function interrupt */
283 int SDIO_Card_EnableInt(LPC_SDMMC_T *pSDMMC, uint32_t func)
284 {
285 int ret;
286 uint32_t val;
287
288 if (func > sdioif->fnum)
289 return SDIO_ERR_INVFUNC;
290
291 ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, &val);
292 if (ret) return ret;
293 val |= (1 << func) | 1;
294 ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, val);
295 if (ret) return ret;
296 pSDMMC->INTMASK |= SDIO_CARD_INT_MSK;
297
298 return 0;
299 }
300
301 /* Disable SDIO function interrupt */
302 int SDIO_Card_DisableInt(LPC_SDMMC_T *pSDMMC, uint32_t func)
303 {
304 int ret;
305 uint32_t val;
306
307 if (func > sdioif->fnum)
308 return SDIO_ERR_INVFUNC;
309
310 ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, &val);
311 if (ret) return ret;
312 val &= ~(1 << func);
313
314 /* Disable master interrupt if it is the only thing enabled */
315 if (val == 1)
316 val = 0;
317 ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x04, val);
318 if (ret) return ret;
319 if (!val)
320 pSDMMC->INTMASK &= ~SDIO_CARD_INT_MSK;
321
322 return 0;
323 }
324
325 /* Initialize the SDIO card */
326 int SDIO_Card_Init(LPC_SDMMC_T *pSDMMC, uint32_t freq)
327 {
328 int ret;
329 uint32_t val;
330
331 /* Set Clock to 400KHz */
332 Chip_SDIF_SetClock(pSDMMC, Chip_Clock_GetBaseClocktHz(CLK_BASE_SDIO), freq);
333 Chip_SDIF_SetCardType(pSDMMC, 0);
334
335 sdioif->wait_evt(pSDMMC, SDIO_WAIT_DELAY, (void *) 100); /* Wait for card to wake up */
336
337 if (sdioif->flag & SDIO_POWER_INIT) {
338 /* Write to the Reset Bit */
339 ret = SDIO_Write_Direct(pSDMMC, SDIO_AREA_CIA, 0x06, 0x08);
340 if (ret) return ret;
341 }
342
343 /* Set Voltage level to 3v3 */
344 ret = SDIO_Card_SetVoltage(pSDMMC);
345 if (ret) return ret;
346
347 /* Set the RCA */
348 ret = SDIO_CARD_SetRCA(pSDMMC);
349 if (ret) return ret;
350
351 /* ==== check card capability ==== */
352 val = 0x02;
353 ret = SDIO_WriteRead_Direct(pSDMMC, SDIO_AREA_CIA, 0x13, &val);
354 if (ret) return ret;
355
356 /* FIXME: Verify */
357 /* FIFO threshold settings for DMA, DMA burst of 4, FIFO watermark at 16 */
358 pSDMMC->FIFOTH = MCI_FIFOTH_DMA_MTS_1 | MCI_FIFOTH_RX_WM(0) | MCI_FIFOTH_TX_WM(1);
359
360 /* Enable internal DMA, burst size of 4, fixed burst */
361 pSDMMC->BMOD = MCI_BMOD_DE | MCI_BMOD_PBL1 | MCI_BMOD_DSL(0);
362
363 /* High Speed Support? */
364 if ((val & 0x03) == 3) {
365 return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_HISPEED, 1);
366 }
367
368 ret = SDIO_Read_Direct(pSDMMC, SDIO_AREA_CIA, 0x08, &val);
369 if (ret) return ret;
370
371 /* Full Speed Support? */
372 if (val & SDIO_CCCR_LSC) {
373 return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_FULLSPEED, 1);
374 }
375
376 /* Low Speed Card */
377 return SDIO_Card_SetMode(pSDMMC, SDIO_CLK_LOWSPEED, val & SDIO_CCCR_4BLS);
378 }
379
380 /* Write given data to register space of the CARD */
381 int SDIO_Write_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t data)
382 {
383 int ret;
384
385 ret = SDIO_Send_Command(pSDMMC, CMD52, (func << 28) | (addr << 9) | (data & 0xFF) | (1UL << 31));
386 if (ret) return ret;
387
388 /* Check response for errors */
389 if(sdioif->response[0] & 0xcb00){
390 /* COM_CRC_ERROR */
391 /* ILLEGAL_CRC_ERROR */
392 /* ERROR */
393 /* RFU FUNCTION_NUMBER */
394 /* OUT_OF_RANGE */
395 /* Response flag error */
396 return SDIO_ERR_READWRITE;
397 }
398 return data != (sdioif->response[0] & 0xFF);
399 }
400
401 /* Write given data to register, and read back the register into data */
402 int SDIO_WriteRead_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t *data)
403 {
404 int ret;
405
406 ret = SDIO_Send_Command(pSDMMC, CMD52, (func << 28) | (1 << 27) | (addr << 9) | ((*data) & 0xFF) | (1UL << 31));
407 if (ret) return ret;
408
409 /* Check response for errors */
410 if(sdioif->response[0] & 0xcb00){
411 /* COM_CRC_ERROR */
412 /* ILLEGAL_CRC_ERROR */
413 /* ERROR */
414 /* RFU FUNCTION_NUMBER */
415 /* OUT_OF_RANGE */
416 /* Response flag error */
417 return SDIO_ERR_READWRITE;
418 }
419 *data = sdioif->response[0] & 0xFF;
420 return 0;
421 }
422
423 /* Read a register from the register address space of the CARD */
424 int SDIO_Read_Direct(LPC_SDMMC_T *pSDMMC, uint32_t func, uint32_t addr, uint32_t *data)
425 {
426 int ret;
427 ret = SDIO_Send_Command(pSDMMC, CMD52, ((func & 7) << 28) | ((addr & 0x1FFFF) << 9));
428 if (ret) return ret;
429
430 /* Check response for errors */
431 if(sdioif->response[0] & 0xcb00){
432 /* COM_CRC_ERROR */
433 /* ILLEGAL_CRC_ERROR */
434 /* ERROR */
435 /* RFU FUNCTION_NUMBER */
436 /* OUT_OF_RANGE */
437 /* Response flag error */
438 return SDIO_ERR_READWRITE;
439 }
440 *data = sdioif->response[0] & 0xFF;
441 return 0;
442 }
443
444 /* Set up the wait and wake call-back functions */
445 void SDIO_Setup_Callback(LPC_SDMMC_T *pSDMMC,
446 void (*wake_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg),
447 uint32_t (*wait_evt)(LPC_SDMMC_T *pSDMMC, uint32_t event, void *arg))
448 {
449 sdioif->wake_evt = wake_evt;
450 sdioif->wait_evt = wait_evt;
451 }
452
453 /* Send and SD Command to the SDIO Card */
454 uint32_t SDIO_Send_Command(LPC_SDMMC_T *pSDMMC, uint32_t cmd, uint32_t arg)
455 {
456 uint32_t ret, ival;
457 uint32_t imsk = pSDMMC->INTMASK;
458 ret = sdioif->wait_evt(pSDMMC, SDIO_START_COMMAND, (void *)(cmd & 0x3F));
459 ival = SDIO_CMD_INT_MSK & ~ret;
460
461 /* Set data interrupts for data commands */
462 if (cmd & SDIO_CMD_DATA) {
463 ival |= SDIO_DATA_INT_MSK;
464 imsk |= SDIO_DATA_INT_MSK;
465 }
466
467 Chip_SDIF_SetIntMask(pSDMMC, ival);
468 Chip_SDIF_SendCmd(pSDMMC, cmd, arg);
469 ret = sdioif->wait_evt(pSDMMC, SDIO_WAIT_COMMAND, 0);
470 if (!ret && (cmd & SDIO_CMD_RESP_R1)) {
471 Chip_SDIF_GetResponse(pSDMMC, &sdioif->response[0]);
472 }
473
474 Chip_SDIF_SetIntMask(pSDMMC, imsk);
475 return ret;
476 }
477
478 /* SDIO Card interrupt handler */
479 void SDIO_Handler(LPC_SDMMC_T *pSDMMC)
480 {
481 uint32_t status = pSDMMC->MINTSTS;
482 uint32_t iclr = 0;
483
484 /* Card Detected */
485 if (status & 1) {
486 sdioif->wake_evt(pSDMMC, SDIO_CARD_DETECT, 0);
487 iclr = 1;
488 }
489
490 /* Command event error */
491 if (status & (SDIO_CMD_INT_MSK & ~4)) {
492 sdioif->wake_evt(pSDMMC, SDIO_CMD_ERR, (void *) (status & (SDIO_CMD_INT_MSK & ~4)));
493 iclr |= status & SDIO_CMD_INT_MSK;
494 } else if (status & 4) {
495 /* Command event done */
496 sdioif->wake_evt(pSDMMC, SDIO_CMD_DONE, (void *) status);
497 iclr |= status & SDIO_CMD_INT_MSK;
498 }
499
500 /* Command event error */
501 if (status & (SDIO_DATA_INT_MSK & ~8)) {
502 sdioif->wake_evt(pSDMMC, SDIO_DATA_ERR, (void *) (status & (SDIO_DATA_INT_MSK & ~8)));
503 iclr |= (status & SDIO_DATA_INT_MSK) | (3 << 4);
504 } else if (status & 8) {
505 /* Command event done */
506 sdioif->wake_evt(pSDMMC, SDIO_DATA_DONE, (void *) status);
507 iclr |= (status & SDIO_DATA_INT_MSK) | (3 << 4);
508 }
509
510 /* Handle Card interrupt */
511 if (status & SDIO_CARD_INT_MSK) {
512 sdioif->wake_evt(pSDMMC, SDIO_CARD_INT, 0);
513 iclr |= status & SDIO_CARD_INT_MSK;
514 }
515
516 /* Clear the interrupts */
517 pSDMMC->RINTSTS = iclr;
518 }