1 /* 2 * (C) Copyright 2007-2011 3 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 4 * Aaron <leafy.myeh@allwinnertech.com> 5 * 6 * MMC driver for allwinner sunxi platform. 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <dm.h> 13 #include <errno.h> 14 #include <malloc.h> 15 #include <mmc.h> 16 #include <asm/io.h> 17 #include <asm/arch/clock.h> 18 #include <asm/arch/cpu.h> 19 #include <asm/arch/gpio.h> 20 #include <asm/arch/mmc.h> 21 #include <asm-generic/gpio.h> 22 23 struct sunxi_mmc_plat { 24 struct mmc_config cfg; 25 struct mmc mmc; 26 }; 27 28 struct sunxi_mmc_priv { 29 unsigned mmc_no; 30 uint32_t *mclkreg; 31 unsigned fatal_err; 32 struct gpio_desc cd_gpio; /* Change Detect GPIO */ 33 int cd_inverted; /* Inverted Card Detect */ 34 struct sunxi_mmc *reg; 35 struct mmc_config cfg; 36 }; 37 38 #if !CONFIG_IS_ENABLED(DM_MMC) 39 /* support 4 mmc hosts */ 40 struct sunxi_mmc_priv mmc_host[4]; 41 42 static int sunxi_mmc_getcd_gpio(int sdc_no) 43 { 44 switch (sdc_no) { 45 case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); 46 case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); 47 case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); 48 case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); 49 } 50 return -EINVAL; 51 } 52 53 static int mmc_resource_init(int sdc_no) 54 { 55 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no]; 56 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 57 int cd_pin, ret = 0; 58 59 debug("init mmc %d resource\n", sdc_no); 60 61 switch (sdc_no) { 62 case 0: 63 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE; 64 priv->mclkreg = &ccm->sd0_clk_cfg; 65 break; 66 case 1: 67 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE; 68 priv->mclkreg = &ccm->sd1_clk_cfg; 69 break; 70 case 2: 71 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE; 72 priv->mclkreg = &ccm->sd2_clk_cfg; 73 break; 74 case 3: 75 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE; 76 priv->mclkreg = &ccm->sd3_clk_cfg; 77 break; 78 default: 79 printf("Wrong mmc number %d\n", sdc_no); 80 return -1; 81 } 82 priv->mmc_no = sdc_no; 83 84 cd_pin = sunxi_mmc_getcd_gpio(sdc_no); 85 if (cd_pin >= 0) { 86 ret = gpio_request(cd_pin, "mmc_cd"); 87 if (!ret) { 88 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP); 89 ret = gpio_direction_input(cd_pin); 90 } 91 } 92 93 return ret; 94 } 95 #endif 96 97 static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) 98 { 99 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; 100 bool new_mode = false; 101 u32 val = 0; 102 103 if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2)) 104 new_mode = true; 105 106 /* 107 * The MMC clock has an extra /2 post-divider when operating in the new 108 * mode. 109 */ 110 if (new_mode) 111 hz = hz * 2; 112 113 if (hz <= 24000000) { 114 pll = CCM_MMC_CTRL_OSCM24; 115 pll_hz = 24000000; 116 } else { 117 #ifdef CONFIG_MACH_SUN9I 118 pll = CCM_MMC_CTRL_PLL_PERIPH0; 119 pll_hz = clock_get_pll4_periph0(); 120 #else 121 pll = CCM_MMC_CTRL_PLL6; 122 pll_hz = clock_get_pll6(); 123 #endif 124 } 125 126 div = pll_hz / hz; 127 if (pll_hz % hz) 128 div++; 129 130 n = 0; 131 while (div > 16) { 132 n++; 133 div = (div + 1) / 2; 134 } 135 136 if (n > 3) { 137 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no, 138 hz); 139 return -1; 140 } 141 142 /* determine delays */ 143 if (hz <= 400000) { 144 oclk_dly = 0; 145 sclk_dly = 0; 146 } else if (hz <= 25000000) { 147 oclk_dly = 0; 148 sclk_dly = 5; 149 #ifdef CONFIG_MACH_SUN9I 150 } else if (hz <= 52000000) { 151 oclk_dly = 5; 152 sclk_dly = 4; 153 } else { 154 /* hz > 52000000 */ 155 oclk_dly = 2; 156 sclk_dly = 4; 157 #else 158 } else if (hz <= 52000000) { 159 oclk_dly = 3; 160 sclk_dly = 4; 161 } else { 162 /* hz > 52000000 */ 163 oclk_dly = 1; 164 sclk_dly = 4; 165 #endif 166 } 167 168 if (new_mode) { 169 #ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE 170 val = CCM_MMC_CTRL_MODE_SEL_NEW; 171 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW); 172 #endif 173 } else { 174 val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) | 175 CCM_MMC_CTRL_SCLK_DLY(sclk_dly); 176 } 177 178 writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) | 179 CCM_MMC_CTRL_M(div) | val, priv->mclkreg); 180 181 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n", 182 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div); 183 184 return 0; 185 } 186 187 static int mmc_update_clk(struct sunxi_mmc_priv *priv) 188 { 189 unsigned int cmd; 190 unsigned timeout_msecs = 2000; 191 unsigned long start = get_timer(0); 192 193 cmd = SUNXI_MMC_CMD_START | 194 SUNXI_MMC_CMD_UPCLK_ONLY | 195 SUNXI_MMC_CMD_WAIT_PRE_OVER; 196 197 writel(cmd, &priv->reg->cmd); 198 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) { 199 if (get_timer(start) > timeout_msecs) 200 return -1; 201 } 202 203 /* clock update sets various irq status bits, clear these */ 204 writel(readl(&priv->reg->rint), &priv->reg->rint); 205 206 return 0; 207 } 208 209 static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc) 210 { 211 unsigned rval = readl(&priv->reg->clkcr); 212 213 /* Disable Clock */ 214 rval &= ~SUNXI_MMC_CLK_ENABLE; 215 writel(rval, &priv->reg->clkcr); 216 if (mmc_update_clk(priv)) 217 return -1; 218 219 /* Set mod_clk to new rate */ 220 if (mmc_set_mod_clk(priv, mmc->clock)) 221 return -1; 222 223 /* Clear internal divider */ 224 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK; 225 writel(rval, &priv->reg->clkcr); 226 227 /* Re-enable Clock */ 228 rval |= SUNXI_MMC_CLK_ENABLE; 229 writel(rval, &priv->reg->clkcr); 230 if (mmc_update_clk(priv)) 231 return -1; 232 233 return 0; 234 } 235 236 static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv, 237 struct mmc *mmc) 238 { 239 debug("set ios: bus_width: %x, clock: %d\n", 240 mmc->bus_width, mmc->clock); 241 242 /* Change clock first */ 243 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) { 244 priv->fatal_err = 1; 245 return -EINVAL; 246 } 247 248 /* Change bus width */ 249 if (mmc->bus_width == 8) 250 writel(0x2, &priv->reg->width); 251 else if (mmc->bus_width == 4) 252 writel(0x1, &priv->reg->width); 253 else 254 writel(0x0, &priv->reg->width); 255 256 return 0; 257 } 258 259 #if !CONFIG_IS_ENABLED(DM_MMC) 260 static int sunxi_mmc_core_init(struct mmc *mmc) 261 { 262 struct sunxi_mmc_priv *priv = mmc->priv; 263 264 /* Reset controller */ 265 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); 266 udelay(1000); 267 268 return 0; 269 } 270 #endif 271 272 static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc, 273 struct mmc_data *data) 274 { 275 const int reading = !!(data->flags & MMC_DATA_READ); 276 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY : 277 SUNXI_MMC_STATUS_FIFO_FULL; 278 unsigned i; 279 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src); 280 unsigned byte_cnt = data->blocksize * data->blocks; 281 unsigned timeout_msecs = byte_cnt >> 8; 282 unsigned long start; 283 284 if (timeout_msecs < 2000) 285 timeout_msecs = 2000; 286 287 /* Always read / write data through the CPU */ 288 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); 289 290 start = get_timer(0); 291 292 for (i = 0; i < (byte_cnt >> 2); i++) { 293 while (readl(&priv->reg->status) & status_bit) { 294 if (get_timer(start) > timeout_msecs) 295 return -1; 296 } 297 298 if (reading) 299 buff[i] = readl(&priv->reg->fifo); 300 else 301 writel(buff[i], &priv->reg->fifo); 302 } 303 304 return 0; 305 } 306 307 static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc, 308 uint timeout_msecs, uint done_bit, const char *what) 309 { 310 unsigned int status; 311 unsigned long start = get_timer(0); 312 313 do { 314 status = readl(&priv->reg->rint); 315 if ((get_timer(start) > timeout_msecs) || 316 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) { 317 debug("%s timeout %x\n", what, 318 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT); 319 return -ETIMEDOUT; 320 } 321 } while (!(status & done_bit)); 322 323 return 0; 324 } 325 326 static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv, 327 struct mmc *mmc, struct mmc_cmd *cmd, 328 struct mmc_data *data) 329 { 330 unsigned int cmdval = SUNXI_MMC_CMD_START; 331 unsigned int timeout_msecs; 332 int error = 0; 333 unsigned int status = 0; 334 unsigned int bytecnt = 0; 335 336 if (priv->fatal_err) 337 return -1; 338 if (cmd->resp_type & MMC_RSP_BUSY) 339 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx); 340 if (cmd->cmdidx == 12) 341 return 0; 342 343 if (!cmd->cmdidx) 344 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; 345 if (cmd->resp_type & MMC_RSP_PRESENT) 346 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE; 347 if (cmd->resp_type & MMC_RSP_136) 348 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE; 349 if (cmd->resp_type & MMC_RSP_CRC) 350 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC; 351 352 if (data) { 353 if ((u32)(long)data->dest & 0x3) { 354 error = -1; 355 goto out; 356 } 357 358 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER; 359 if (data->flags & MMC_DATA_WRITE) 360 cmdval |= SUNXI_MMC_CMD_WRITE; 361 if (data->blocks > 1) 362 cmdval |= SUNXI_MMC_CMD_AUTO_STOP; 363 writel(data->blocksize, &priv->reg->blksz); 364 writel(data->blocks * data->blocksize, &priv->reg->bytecnt); 365 } 366 367 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no, 368 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg); 369 writel(cmd->cmdarg, &priv->reg->arg); 370 371 if (!data) 372 writel(cmdval | cmd->cmdidx, &priv->reg->cmd); 373 374 /* 375 * transfer data and check status 376 * STATREG[2] : FIFO empty 377 * STATREG[3] : FIFO full 378 */ 379 if (data) { 380 int ret = 0; 381 382 bytecnt = data->blocksize * data->blocks; 383 debug("trans data %d bytes\n", bytecnt); 384 writel(cmdval | cmd->cmdidx, &priv->reg->cmd); 385 ret = mmc_trans_data_by_cpu(priv, mmc, data); 386 if (ret) { 387 error = readl(&priv->reg->rint) & 388 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT; 389 error = -ETIMEDOUT; 390 goto out; 391 } 392 } 393 394 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, 395 "cmd"); 396 if (error) 397 goto out; 398 399 if (data) { 400 timeout_msecs = 120; 401 debug("cacl timeout %x msec\n", timeout_msecs); 402 error = mmc_rint_wait(priv, mmc, timeout_msecs, 403 data->blocks > 1 ? 404 SUNXI_MMC_RINT_AUTO_COMMAND_DONE : 405 SUNXI_MMC_RINT_DATA_OVER, 406 "data"); 407 if (error) 408 goto out; 409 } 410 411 if (cmd->resp_type & MMC_RSP_BUSY) { 412 unsigned long start = get_timer(0); 413 timeout_msecs = 2000; 414 415 do { 416 status = readl(&priv->reg->status); 417 if (get_timer(start) > timeout_msecs) { 418 debug("busy timeout\n"); 419 error = -ETIMEDOUT; 420 goto out; 421 } 422 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY); 423 } 424 425 if (cmd->resp_type & MMC_RSP_136) { 426 cmd->response[0] = readl(&priv->reg->resp3); 427 cmd->response[1] = readl(&priv->reg->resp2); 428 cmd->response[2] = readl(&priv->reg->resp1); 429 cmd->response[3] = readl(&priv->reg->resp0); 430 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n", 431 cmd->response[3], cmd->response[2], 432 cmd->response[1], cmd->response[0]); 433 } else { 434 cmd->response[0] = readl(&priv->reg->resp0); 435 debug("mmc resp 0x%08x\n", cmd->response[0]); 436 } 437 out: 438 if (error < 0) { 439 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); 440 mmc_update_clk(priv); 441 } 442 writel(0xffffffff, &priv->reg->rint); 443 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET, 444 &priv->reg->gctrl); 445 446 return error; 447 } 448 449 #if !CONFIG_IS_ENABLED(DM_MMC) 450 static int sunxi_mmc_set_ios_legacy(struct mmc *mmc) 451 { 452 struct sunxi_mmc_priv *priv = mmc->priv; 453 454 return sunxi_mmc_set_ios_common(priv, mmc); 455 } 456 457 static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd, 458 struct mmc_data *data) 459 { 460 struct sunxi_mmc_priv *priv = mmc->priv; 461 462 return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data); 463 } 464 465 static int sunxi_mmc_getcd_legacy(struct mmc *mmc) 466 { 467 struct sunxi_mmc_priv *priv = mmc->priv; 468 int cd_pin; 469 470 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no); 471 if (cd_pin < 0) 472 return 1; 473 474 return !gpio_get_value(cd_pin); 475 } 476 477 static const struct mmc_ops sunxi_mmc_ops = { 478 .send_cmd = sunxi_mmc_send_cmd_legacy, 479 .set_ios = sunxi_mmc_set_ios_legacy, 480 .init = sunxi_mmc_core_init, 481 .getcd = sunxi_mmc_getcd_legacy, 482 }; 483 484 struct mmc *sunxi_mmc_init(int sdc_no) 485 { 486 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 487 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no]; 488 struct mmc_config *cfg = &priv->cfg; 489 int ret; 490 491 memset(priv, '\0', sizeof(struct sunxi_mmc_priv)); 492 493 cfg->name = "SUNXI SD/MMC"; 494 cfg->ops = &sunxi_mmc_ops; 495 496 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 497 cfg->host_caps = MMC_MODE_4BIT; 498 #if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) 499 if (sdc_no == 2) 500 cfg->host_caps = MMC_MODE_8BIT; 501 #endif 502 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 503 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 504 505 cfg->f_min = 400000; 506 cfg->f_max = 52000000; 507 508 if (mmc_resource_init(sdc_no) != 0) 509 return NULL; 510 511 /* config ahb clock */ 512 debug("init mmc %d clock and io\n", sdc_no); 513 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); 514 515 #ifdef CONFIG_SUNXI_GEN_SUN6I 516 /* unassert reset */ 517 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); 518 #endif 519 #if defined(CONFIG_MACH_SUN9I) 520 /* sun9i has a mmc-common module, also set the gate and reset there */ 521 writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET, 522 SUNXI_MMC_COMMON_BASE + 4 * sdc_no); 523 #endif 524 ret = mmc_set_mod_clk(priv, 24000000); 525 if (ret) 526 return NULL; 527 528 return mmc_create(cfg, priv); 529 } 530 #else 531 532 static int sunxi_mmc_set_ios(struct udevice *dev) 533 { 534 struct sunxi_mmc_plat *plat = dev_get_platdata(dev); 535 struct sunxi_mmc_priv *priv = dev_get_priv(dev); 536 537 return sunxi_mmc_set_ios_common(priv, &plat->mmc); 538 } 539 540 static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, 541 struct mmc_data *data) 542 { 543 struct sunxi_mmc_plat *plat = dev_get_platdata(dev); 544 struct sunxi_mmc_priv *priv = dev_get_priv(dev); 545 546 return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data); 547 } 548 549 static int sunxi_mmc_getcd(struct udevice *dev) 550 { 551 struct sunxi_mmc_priv *priv = dev_get_priv(dev); 552 553 if (dm_gpio_is_valid(&priv->cd_gpio)) { 554 int cd_state = dm_gpio_get_value(&priv->cd_gpio); 555 556 return cd_state ^ priv->cd_inverted; 557 } 558 return 1; 559 } 560 561 static const struct dm_mmc_ops sunxi_mmc_ops = { 562 .send_cmd = sunxi_mmc_send_cmd, 563 .set_ios = sunxi_mmc_set_ios, 564 .get_cd = sunxi_mmc_getcd, 565 }; 566 567 static int sunxi_mmc_probe(struct udevice *dev) 568 { 569 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 570 struct sunxi_mmc_plat *plat = dev_get_platdata(dev); 571 struct sunxi_mmc_priv *priv = dev_get_priv(dev); 572 struct mmc_config *cfg = &plat->cfg; 573 struct ofnode_phandle_args args; 574 u32 *gate_reg; 575 int bus_width, ret; 576 577 cfg->name = dev->name; 578 bus_width = dev_read_u32_default(dev, "bus-width", 1); 579 580 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 581 cfg->host_caps = 0; 582 if (bus_width == 8) 583 cfg->host_caps |= MMC_MODE_8BIT; 584 if (bus_width >= 4) 585 cfg->host_caps |= MMC_MODE_4BIT; 586 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 587 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 588 589 cfg->f_min = 400000; 590 cfg->f_max = 52000000; 591 592 priv->reg = (void *)dev_read_addr(dev); 593 594 /* We don't have a sunxi clock driver so find the clock address here */ 595 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, 596 1, &args); 597 if (ret) 598 return ret; 599 priv->mclkreg = (u32 *)ofnode_get_addr(args.node); 600 601 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0, 602 0, &args); 603 if (ret) 604 return ret; 605 gate_reg = (u32 *)ofnode_get_addr(args.node); 606 setbits_le32(gate_reg, 1 << args.args[0]); 607 priv->mmc_no = args.args[0] - 8; 608 609 ret = mmc_set_mod_clk(priv, 24000000); 610 if (ret) 611 return ret; 612 613 /* This GPIO is optional */ 614 if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, 615 GPIOD_IS_IN)) { 616 int cd_pin = gpio_get_number(&priv->cd_gpio); 617 618 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP); 619 } 620 621 /* Check if card detect is inverted */ 622 priv->cd_inverted = dev_read_bool(dev, "cd-inverted"); 623 624 upriv->mmc = &plat->mmc; 625 626 /* Reset controller */ 627 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); 628 udelay(1000); 629 630 return 0; 631 } 632 633 static int sunxi_mmc_bind(struct udevice *dev) 634 { 635 struct sunxi_mmc_plat *plat = dev_get_platdata(dev); 636 637 return mmc_bind(dev, &plat->mmc, &plat->cfg); 638 } 639 640 static const struct udevice_id sunxi_mmc_ids[] = { 641 { .compatible = "allwinner,sun5i-a13-mmc" }, 642 { } 643 }; 644 645 U_BOOT_DRIVER(sunxi_mmc_drv) = { 646 .name = "sunxi_mmc", 647 .id = UCLASS_MMC, 648 .of_match = sunxi_mmc_ids, 649 .bind = sunxi_mmc_bind, 650 .probe = sunxi_mmc_probe, 651 .ops = &sunxi_mmc_ops, 652 .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat), 653 .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv), 654 }; 655 #endif 656