1 /*
2 * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-07-01 lik first version
9 */
10
11 #include "drv_sdio.h"
12
13 #ifdef RT_USING_SDIO
14 #ifdef BSP_USING_SDIO
15
16 //#define DRV_DEBUG
17 #define LOG_TAG "drv.sdio"
18 #include <drv_log.h>
19
20 #define SDIO_BUFF_SIZE 4096
21 #define SDIO_ALIGN_LEN 4
22
23 #ifndef SDIO_MAX_FREQ
24 #define SDIO_MAX_FREQ (37500000)
25 #endif
26
27 struct swm_sdio_pkg
28 {
29 struct rt_mmcsd_cmd *cmd;
30 void *buff;
31 rt_uint32_t flag;
32 };
33
34 typedef rt_err_t (*sdio_txconfig)(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size);
35 typedef rt_err_t (*sdio_rxconfig)(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size);
36 typedef rt_uint32_t (*sdio_clk_get)(SDIO_TypeDef *swm_sdio);
37
38 struct swm_sdio_des
39 {
40 SDIO_TypeDef *swm_sdio;
41 sdio_txconfig txconfig;
42 sdio_rxconfig rxconfig;
43 sdio_clk_get clk_get;
44 };
45
46 static struct rt_mmcsd_host *host;
47
48 #define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&_sdio->mutex, RT_WAITING_FOREVER)
49 #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&_sdio->mutex);
50
51 struct swm_sdio_device
52 {
53 struct rt_mmcsd_host *host;
54 struct swm_sdio_des sdio_des;
55 struct rt_event event;
56 struct rt_mutex mutex;
57 struct swm_sdio_pkg *pkg;
58 };
59
rt_align(SDIO_ALIGN_LEN)60 rt_align(SDIO_ALIGN_LEN)
61 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
62
63 /**
64 * @brief This function wait sdio completed.
65 * @param sdio swm_sdio_device
66 * @retval None
67 */
68 static void swm_sdio_wait_completed(struct swm_sdio_device *sdio)
69 {
70 rt_uint32_t status;
71 struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
72 struct rt_mmcsd_data *data = cmd->data;
73 SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
74
75 if (rt_event_recv(&sdio->event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
76 rt_tick_from_millisecond(2000), &status) != RT_EOK)
77 {
78 LOG_E("wait completed timeout");
79 cmd->err = -RT_ETIMEOUT;
80 return;
81 }
82
83 if (sdio->pkg == RT_NULL)
84 {
85 return;
86 }
87
88 if (resp_type(cmd) == RESP_NONE)
89 {
90 ;
91 }
92 else if (resp_type(cmd) == RESP_R2)
93 {
94 LOG_D("R2");
95 cmd->resp[0] = (swm_sdio->RESP[3] << 8) + ((swm_sdio->RESP[2] >> 24) & 0xFF);
96 cmd->resp[1] = (swm_sdio->RESP[2] << 8) + ((swm_sdio->RESP[1] >> 24) & 0xFF);
97 cmd->resp[2] = (swm_sdio->RESP[1] << 8) + ((swm_sdio->RESP[0] >> 24) & 0xFF);
98 cmd->resp[3] = (swm_sdio->RESP[0] << 8) + 0x00;
99 }
100 else
101 {
102 cmd->resp[0] = swm_sdio->RESP[0];
103 }
104
105 if (status & SDIO_IF_ERROR_Msk)
106 {
107 if ((status & SDIO_IF_CMDCRCERR_Msk) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
108 {
109 cmd->err = RT_EOK;
110 }
111 else
112 {
113 cmd->err = -RT_ERROR;
114 }
115
116 if (status & SDIO_IF_CMDCRCERR_Msk)
117 {
118 SDIO->CR2 |= (1 << SDIO_CR2_RSTCMD_Pos);
119 data->err = -RT_ERROR;
120 }
121
122 if (status & SDIO_IF_CMDTIMEOUT_Msk)
123 {
124 SDIO->CR2 |= (1 << SDIO_CR2_RSTCMD_Pos);
125 cmd->err = -RT_ETIMEOUT;
126 }
127
128 if (status & SDIO_IF_DATCRCERR_Msk)
129 {
130 SDIO->CR2 |= (1 << SDIO_CR2_RSTDAT_Pos);
131 data->err = -RT_ERROR;
132 }
133
134 if (status & SDIO_IF_DATTIMEOUT_Msk)
135 {
136 SDIO->CR2 |= (1 << SDIO_CR2_RSTDAT_Pos);
137 data->err = -RT_ETIMEOUT;
138 }
139
140 if (cmd->err == RT_EOK)
141 {
142 LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
143 }
144 else
145 {
146 LOG_D("err:0x%08x, %s%s%s%s%s cmd:%d arg:0x%08x rw:%c len:%d blksize:%d",
147 status,
148 status & SDIO_IF_CMDCRCERR_Msk ? "CCRCFAIL " : "",
149 status & SDIO_IF_DATCRCERR_Msk ? "DCRCFAIL " : "",
150 status & SDIO_IF_CMDTIMEOUT_Msk ? "CTIMEOUT " : "",
151 status & SDIO_IF_DATTIMEOUT_Msk ? "DTIMEOUT " : "",
152 status == 0 ? "NULL" : "",
153 cmd->cmd_code,
154 cmd->arg,
155 data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
156 data ? data->blks * data->blksize : 0,
157 data ? data->blksize : 0);
158 }
159 }
160 else
161 {
162 cmd->err = RT_EOK;
163 LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
164 }
165 }
166
167 /**
168 * @brief This function transfer data by dma.
169 * @param sdio swm_sdio_device
170 * @param pkg sdio package
171 * @retval None
172 */
swm_sdio_transfer(struct swm_sdio_device * sdio,struct swm_sdio_pkg * pkg)173 static void swm_sdio_transfer(struct swm_sdio_device *sdio, struct swm_sdio_pkg *pkg)
174 {
175 struct rt_mmcsd_data *data;
176 int size;
177 void *buff;
178
179 if ((RT_NULL == pkg) || (RT_NULL == sdio))
180 {
181 LOG_E("swm_sdio_transfer invalid args");
182 return;
183 }
184
185 data = pkg->cmd->data;
186 if (RT_NULL == data)
187 {
188 LOG_E("swm_sdio_transfer invalid args");
189 return;
190 }
191
192 buff = pkg->buff;
193 if (RT_NULL == buff)
194 {
195 LOG_E("swm_sdio_transfer invalid args");
196 return;
197 }
198
199 size = data->blks * data->blksize;
200
201 if (data->flags & DATA_DIR_WRITE)
202 {
203 sdio->sdio_des.txconfig(pkg, (rt_uint32_t *)buff, size);
204 }
205 else if (data->flags & DATA_DIR_READ)
206 {
207 sdio->sdio_des.rxconfig(pkg, (rt_uint32_t *)buff, size);
208 }
209 }
210
211 /**
212 * @brief This function send command.
213 * @param sdio swm_sdio_device
214 * @param pkg sdio package
215 * @retval None
216 */
swm_sdio_send_command(struct swm_sdio_device * sdio,struct swm_sdio_pkg * pkg)217 static void swm_sdio_send_command(struct swm_sdio_device *sdio, struct swm_sdio_pkg *pkg)
218 {
219 struct rt_mmcsd_cmd *cmd = pkg->cmd;
220 struct rt_mmcsd_data *data = cmd->data;
221 SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
222 rt_uint32_t reg_cmd;
223
224 /* save pkg */
225 sdio->pkg = pkg;
226
227 LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
228 cmd->cmd_code,
229 cmd->arg,
230 resp_type(cmd) == RESP_NONE ? "NONE" : "",
231 resp_type(cmd) == RESP_R1 ? "R1" : "",
232 resp_type(cmd) == RESP_R1B ? "R1B" : "",
233 resp_type(cmd) == RESP_R2 ? "R2" : "",
234 resp_type(cmd) == RESP_R3 ? "R3" : "",
235 resp_type(cmd) == RESP_R4 ? "R4" : "",
236 resp_type(cmd) == RESP_R5 ? "R5" : "",
237 resp_type(cmd) == RESP_R6 ? "R6" : "",
238 resp_type(cmd) == RESP_R7 ? "R7" : "",
239 data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
240 data ? data->blks * data->blksize : 0,
241 data ? data->blksize : 0);
242
243 /* config cmd reg */
244 reg_cmd = (cmd->cmd_code << SDIO_CMD_CMDINDX_Pos) |
245 (0 << SDIO_CMD_CMDTYPE_Pos) |
246 (0 << SDIO_CMD_IDXCHECK_Pos) |
247 (0 << SDIO_CMD_CRCCHECK_Pos) |
248 (0 << SDIO_CMD_DMAEN_Pos);
249 if (resp_type(cmd) == RESP_NONE)
250 reg_cmd |= SD_RESP_NO << SDIO_CMD_RESPTYPE_Pos;
251 else if (resp_type(cmd) == RESP_R2)
252 reg_cmd |= SD_RESP_128b << SDIO_CMD_RESPTYPE_Pos;
253 else
254 reg_cmd |= SD_RESP_32b << SDIO_CMD_RESPTYPE_Pos;
255
256 /* config data reg */
257 if (data != RT_NULL)
258 {
259 rt_uint32_t dir = 0;
260 dir = (data->flags & DATA_DIR_READ) ? 1 : 0;
261
262 swm_sdio->BLK = (data->blks << SDIO_BLK_COUNT_Pos) | (data->blksize << SDIO_BLK_SIZE_Pos);
263
264 reg_cmd |= (1 << SDIO_CMD_HAVEDATA_Pos) |
265 (dir << SDIO_CMD_DIRREAD_Pos) |
266 ((data->blks > 1) << SDIO_CMD_MULTBLK_Pos) |
267 ((data->blks > 1) << SDIO_CMD_BLKCNTEN_Pos) |
268 (0 << SDIO_CMD_AUTOCMD12_Pos);
269 }
270 else
271 {
272 reg_cmd |= (0 << SDIO_CMD_HAVEDATA_Pos);
273 }
274
275 /* send cmd */
276 swm_sdio->ARG = cmd->arg;
277 swm_sdio->CMD = reg_cmd;
278
279 /* transfer config */
280 if (data != RT_NULL)
281 {
282 swm_sdio_transfer(sdio, pkg);
283 }
284
285 /* wait completed */
286 swm_sdio_wait_completed(sdio);
287
288 /* clear pkg */
289 sdio->pkg = RT_NULL;
290 }
291
292 /**
293 * @brief This function send sdio request.
294 * @param sdio swm_sdio_device
295 * @param req request
296 * @retval None
297 */
swm_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)298 static void swm_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
299 {
300 struct swm_sdio_pkg pkg;
301 struct swm_sdio_device *sdio = host->private_data;
302 struct rt_mmcsd_data *data;
303
304 RTHW_SDIO_LOCK(sdio);
305
306 if (req->cmd != RT_NULL)
307 {
308 rt_memset(&pkg, 0, sizeof(pkg));
309 data = req->cmd->data;
310 pkg.cmd = req->cmd;
311
312 if (data != RT_NULL)
313 {
314 rt_uint32_t size = data->blks * data->blksize;
315
316 RT_ASSERT(size <= SDIO_BUFF_SIZE);
317
318 pkg.buff = data->buf;
319 if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
320 {
321 pkg.buff = cache_buf;
322 if (data->flags & DATA_DIR_WRITE)
323 {
324 rt_memcpy(cache_buf, data->buf, size);
325 }
326 }
327 }
328
329 swm_sdio_send_command(sdio, &pkg);
330
331 if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
332 {
333 rt_memcpy(data->buf, cache_buf, data->blksize * data->blks);
334 }
335 }
336
337 if (req->stop != RT_NULL)
338 {
339 rt_memset(&pkg, 0, sizeof(pkg));
340 pkg.cmd = req->stop;
341 swm_sdio_send_command(sdio, &pkg);
342 }
343
344 RTHW_SDIO_UNLOCK(sdio);
345
346 mmcsd_req_complete(sdio->host);
347 }
348
349 /**
350 * @brief This function config sdio.
351 * @param host rt_mmcsd_host
352 * @param io_cfg rt_mmcsd_io_cfg
353 * @retval None
354 */
swm_sdio_set_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)355 static void swm_sdio_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
356 {
357 rt_uint32_t clkcr, div, clk_src;
358 rt_uint32_t clk = io_cfg->clock;
359 struct swm_sdio_device *sdio = host->private_data;
360 SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
361
362 clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.swm_sdio);
363 if (clk_src < 400 * 1000)
364 {
365 LOG_E("The clock rate is too low! rata:%d", clk_src);
366 return;
367 }
368
369 if (clk > host->freq_max)
370 clk = host->freq_max;
371
372 if (clk > clk_src)
373 {
374 LOG_W("Setting rate is greater than clock source rate.");
375 clk = clk_src;
376 }
377
378 LOG_D("clk:%d width:%s%s%s power:%s%s%s",
379 clk,
380 io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
381 io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
382 io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
383 io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
384 io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
385 io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
386
387 RTHW_SDIO_LOCK(sdio);
388
389 swm_sdio->CR1 = (1 << SDIO_CR1_CDSRC_Pos) | (7 << SDIO_CR1_VOLT_Pos);
390 if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
391 {
392 swm_sdio->CR1 |= (1 << SDIO_CR1_8BIT_Pos);
393 }
394 else
395 {
396 swm_sdio->CR1 &= ~SDIO_CR1_8BIT_Msk;
397 if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
398 {
399 swm_sdio->CR1 |= (1 << SDIO_CR1_4BIT_Pos);
400 }
401 else
402 {
403 swm_sdio->CR1 &= ~SDIO_CR1_4BIT_Msk;
404 }
405 }
406 switch (io_cfg->power_mode)
407 {
408 case MMCSD_POWER_OFF:
409 swm_sdio->CR1 &= ~SDIO_CR1_PWRON_Msk;
410 break;
411 case MMCSD_POWER_UP:
412 case MMCSD_POWER_ON:
413 swm_sdio->CR1 |= (1 << SDIO_CR1_PWRON_Pos);
414 break;
415 default:
416 LOG_W("unknown power_mode %d", io_cfg->power_mode);
417 break;
418 }
419
420 div = clk_src / clk;
421 if ((clk == 0) || (div == 0))
422 {
423 clkcr = 0;
424 }
425 else
426 {
427 if (div > 128)
428 clkcr = 0x80;
429 else if (div > 64)
430 clkcr = 0x40;
431 else if (div > 32)
432 clkcr = 0x20;
433 else if (div > 16)
434 clkcr = 0x10;
435 else if (div > 8)
436 clkcr = 0x08;
437 else if (div > 4)
438 clkcr = 0x04;
439 else if (div > 2)
440 clkcr = 0x02;
441 else if (div > 1)
442 clkcr = 0x01;
443 else
444 clkcr = 0x00;
445 }
446
447 SDIO->CR2 = (1 << SDIO_CR2_CLKEN_Pos) |
448 (1 << SDIO_CR2_SDCLKEN_Pos) |
449 (clkcr << SDIO_CR2_SDCLKDIV_Pos) |
450 (0xC << SDIO_CR2_TIMEOUT_Pos); // 2**25 SDIO_CLK
451
452 while ((SDIO->CR2 & SDIO_CR2_CLKRDY_Msk) == 0)
453 ;
454
455 RTHW_SDIO_UNLOCK(sdio);
456 }
457
458 /**
459 * @brief This function delect sdcard.
460 * @param host rt_mmcsd_host
461 * @retval 0x01
462 */
swm_sdio_get_card_status(struct rt_mmcsd_host * host)463 static rt_int32_t swm_sdio_get_card_status(struct rt_mmcsd_host *host)
464 {
465 LOG_D("try to detect device");
466 return 0x01;
467 }
468
469 /**
470 * @brief This function update sdio interrupt.
471 * @param host rt_mmcsd_host
472 * @param enable
473 * @retval None
474 */
swm_sdio_enable_irq(struct rt_mmcsd_host * host,rt_int32_t enable)475 void swm_sdio_enable_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
476 {
477 struct swm_sdio_device *sdio = host->private_data;
478 SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
479
480 if (enable)
481 {
482 LOG_D("enable sdio irq");
483 swm_sdio->IM = 0xFFFFFFFF;
484 swm_sdio->IE = 0xFFFF000F;
485 }
486 else
487 {
488 LOG_D("disable sdio irq");
489 swm_sdio->IM &= ~0xFFFFFFFF;
490 swm_sdio->IE &= ~0xFFFFFFFF;
491 }
492 }
493
494 static const struct rt_mmcsd_host_ops swm_sdio_ops =
495 {
496 .request = swm_sdio_request,
497 .set_iocfg = swm_sdio_set_iocfg,
498 .get_card_status = swm_sdio_get_card_status,
499 .enable_sdio_irq = swm_sdio_enable_irq,
500 };
501
swm_sdio_host_create(struct swm_sdio_des * sdio_des)502 struct rt_mmcsd_host *swm_sdio_host_create(struct swm_sdio_des *sdio_des)
503 {
504 struct rt_mmcsd_host *host;
505 struct swm_sdio_device *sdio = RT_NULL;
506
507 if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
508 {
509 LOG_E("L:%d F:%s %s %s %s",
510 (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
511 (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
512 (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : ""));
513 return RT_NULL;
514 }
515
516 sdio = rt_malloc(sizeof(struct swm_sdio_device));
517 if (sdio == RT_NULL)
518 {
519 LOG_E("L:%d F:%s malloc swm_sdio_device fail");
520 return RT_NULL;
521 }
522 rt_memset(sdio, 0, sizeof(struct swm_sdio_device));
523
524 host = mmcsd_alloc_host();
525 if (host == RT_NULL)
526 {
527 LOG_E("L:%d F:%s mmcsd alloc host fail");
528 rt_free(sdio);
529 return RT_NULL;
530 }
531
532 rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct swm_sdio_des));
533
534 rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
535 rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO);
536
537 /* set host defautl attributes */
538 host->ops = &swm_sdio_ops;
539 host->freq_min = 400 * 1000;
540 host->freq_max = SDIO_MAX_FREQ;
541 host->valid_ocr = 0X00FFFF80; /* The voltage range supported is 1.65v-3.6v */
542 #ifndef SDIO_USING_1_BIT
543 host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
544 #else
545 host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
546 #endif
547 host->max_seg_size = SDIO_BUFF_SIZE;
548 host->max_dma_segs = 1;
549 host->max_blk_size = 512;
550 host->max_blk_count = 512;
551
552 /* link up host and sdio */
553 sdio->host = host;
554 host->private_data = sdio;
555
556 swm_sdio_enable_irq(host, 1);
557
558 /* ready to change */
559 mmcsd_change(host);
560
561 return host;
562 }
563
swm_sdio_clock_get(SDIO_TypeDef * swm_sdio)564 static rt_uint32_t swm_sdio_clock_get(SDIO_TypeDef *swm_sdio)
565 {
566 uint32_t prediv;
567 switch((SYS->CLKSEL & SYS_CLKSEL_SDIO_Msk) >> SYS_CLKSEL_SDIO_Pos)
568 {
569 case 0: prediv = 1; break;
570 case 1: prediv = 3; break;
571 case 2: prediv = 2; break;
572 case 3: prediv = 0; break;
573 }
574 return (SystemCoreClock / (1 << prediv));
575 }
576
swm_sdio_rxconfig(struct swm_sdio_pkg * pkg,rt_uint32_t * buff,int size)577 static rt_err_t swm_sdio_rxconfig(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size)
578 {
579 struct rt_mmcsd_cmd *cmd = pkg->cmd;
580 struct rt_mmcsd_data *data = cmd->data;
581 int offset = 0;
582 for (uint32_t i = 0; i < data->blks; i++)
583 {
584 offset = i* data->blksize / 4;
585 while ((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0)
586 __NOP();
587 SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
588 for (uint32_t j = 0; j < data->blksize / 4; j++)
589 {
590 buff[offset + j] = SDIO->DATA;
591 }
592 }
593 return RT_EOK;
594 }
595
swm_sdio_txconfig(struct swm_sdio_pkg * pkg,rt_uint32_t * buff,int size)596 static rt_err_t swm_sdio_txconfig(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size)
597 {
598 struct rt_mmcsd_cmd *cmd = pkg->cmd;
599 struct rt_mmcsd_data *data = cmd->data;
600 int offset = 0;
601 for (uint32_t i = 0; i < data->blks; i++)
602 {
603 offset = i* data->blksize / 4;
604 while ((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0)
605 __NOP();
606 SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
607 for (uint32_t j = 0; j < data->blksize / 4; j++)
608 {
609 SDIO->DATA = buff[offset + j];
610 }
611 }
612 return RT_EOK;
613 }
614
615 /**
616 * @brief This function interrupt process function.
617 * @param host rt_mmcsd_host
618 * @retval None
619 */
swm_sdio_irq_process(struct rt_mmcsd_host * host)620 static void swm_sdio_irq_process(struct rt_mmcsd_host *host)
621 {
622 int complete = 0;
623 struct swm_sdio_device *sdio = host->private_data;
624 SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
625 rt_uint32_t intstatus = swm_sdio->IF;
626
627 if (intstatus & SDIO_IF_ERROR_Msk)
628 {
629 swm_sdio->IF = 0xFFFFFFFF;
630 complete = 1;
631 }
632 else
633 {
634 if (intstatus & SDIO_IF_CMDDONE_Msk)
635 {
636 swm_sdio->IF = SDIO_IF_CMDDONE_Msk;
637 if (sdio->pkg != RT_NULL)
638 {
639 if (!sdio->pkg->cmd->data)
640 {
641 complete = 1;
642 }
643 }
644 }
645
646 if (intstatus & SDIO_IF_TRXDONE_Msk)
647 {
648 swm_sdio->IF = SDIO_IF_TRXDONE_Msk;
649 complete = 1;
650 }
651 }
652
653 if (complete)
654 {
655 rt_event_send(&sdio->event, intstatus);
656 }
657 }
658
SDIO_Handler(void)659 void SDIO_Handler(void)
660 {
661 /* enter interrupt */
662 rt_interrupt_enter();
663 /* Process All SDIO Interrupt Sources */
664 swm_sdio_irq_process(host);
665 /* leave interrupt */
666 rt_interrupt_leave();
667 }
668
swm_sdio_init(void)669 int swm_sdio_init(void)
670 {
671 int result = RT_EOK;
672
673 struct swm_sdio_des sdio_des;
674
675 PORT_Init(PORTM, PIN2, PORTM_PIN2_SD_CLK, 0);
676 PORT_Init(PORTM, PIN4, PORTM_PIN4_SD_CMD, 1);
677 PORT_Init(PORTM, PIN5, PORTM_PIN5_SD_D0, 1);
678 PORT_Init(PORTM, PIN6, PORTM_PIN6_SD_D1, 1);
679 PORT_Init(PORTN, PIN0, PORTN_PIN0_SD_D2, 1);
680 PORT_Init(PORTN, PIN1, PORTN_PIN1_SD_D3, 1);
681
682 NVIC_EnableIRQ(SDIO_IRQn);
683 SYS->CLKSEL &= ~SYS_CLKSEL_SDIO_Msk;
684 if (SystemCoreClock > 80000000) //SDIO时钟需要小于52MHz
685 SYS->CLKSEL |= (2 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 4
686 else
687 SYS->CLKSEL |= (0 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 2
688
689 SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_SDIO_Pos);
690
691 SDIO->CR2 = (1 << SDIO_CR2_RSTALL_Pos);
692
693 NVIC_EnableIRQ(SDIO_IRQn);
694 sdio_des.clk_get = swm_sdio_clock_get;
695 sdio_des.swm_sdio = SDIO;
696 sdio_des.rxconfig = swm_sdio_rxconfig;
697 sdio_des.txconfig = swm_sdio_txconfig;
698
699 host = swm_sdio_host_create(&sdio_des);
700 if (host == RT_NULL)
701 {
702 LOG_E("host create fail.");
703 result = -1;
704 }
705 else
706 {
707 LOG_D("host create success.");
708 result = 0;
709 }
710 return result;
711 }
712 INIT_DEVICE_EXPORT(swm_sdio_init);
713
714 #endif /* BSP_USING_SDIO */
715 #endif /* RT_USING_SDIO */
716