1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2007-2011
4 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
5 * Aaron <leafy.myeh@allwinnertech.com>
7 * MMC driver for allwinner sunxi platform.
9 * This driver is used by the (ARM) SPL with the legacy MMC interface, and
10 * by U-Boot proper using the full DM interface. The actual hardware access
11 * code is common, and comes first in this file.
12 * The legacy MMC interface implementation comes next, followed by the
13 * proper DM_MMC implementation at the end.
26 #include <asm/arch/clock.h>
27 #include <asm/arch/cpu.h>
28 #include <asm/arch/mmc.h>
29 #include <linux/delay.h>
31 #ifndef CCM_MMC_CTRL_MODE_SEL_NEW
32 #define CCM_MMC_CTRL_MODE_SEL_NEW 0
35 struct sunxi_mmc_plat
{
36 struct mmc_config cfg
;
40 struct sunxi_mmc_priv
{
44 struct gpio_desc cd_gpio
; /* Change Detect GPIO */
45 struct sunxi_mmc
*reg
;
46 struct mmc_config cfg
;
50 * All A64 and later MMC controllers feature auto-calibration. This would
51 * normally be detected via the compatible string, but we need something
52 * which works in the SPL as well.
54 static bool sunxi_mmc_can_calibrate(void)
56 return IS_ENABLED(CONFIG_MACH_SUN50I
) ||
57 IS_ENABLED(CONFIG_MACH_SUN50I_H5
) ||
58 IS_ENABLED(CONFIG_SUN50I_GEN_H6
) ||
59 IS_ENABLED(CONFIG_MACH_SUN8I_R40
);
62 static int mmc_set_mod_clk(struct sunxi_mmc_priv
*priv
, unsigned int hz
)
64 unsigned int pll
, pll_hz
, div
, n
, oclk_dly
, sclk_dly
;
65 bool new_mode
= IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE
);
68 /* A83T support new mode only on eMMC */
69 if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T
) && priv
->mmc_no
!= 2)
73 pll
= CCM_MMC_CTRL_OSCM24
;
76 #ifdef CONFIG_MACH_SUN9I
77 pll
= CCM_MMC_CTRL_PLL_PERIPH0
;
78 pll_hz
= clock_get_pll4_periph0();
81 * SoCs since the A64 (H5, H6, H616) actually use the doubled
82 * rate of PLL6/PERIPH0 as an input clock, but compensate for
83 * that with a fixed post-divider of 2 in the mod clock.
84 * This cancels each other out, so for simplicity we just
85 * pretend it's always PLL6 without a post divider here.
87 pll
= CCM_MMC_CTRL_PLL6
;
88 pll_hz
= clock_get_pll6();
103 printf("mmc %u error cannot set clock to %u\n", priv
->mmc_no
,
108 /* determine delays */
112 } else if (hz
<= 25000000) {
116 if (IS_ENABLED(CONFIG_MACH_SUN9I
)) {
131 val
|= CCM_MMC_CTRL_MODE_SEL_NEW
;
132 setbits_le32(&priv
->reg
->ntsr
, SUNXI_MMC_NTSR_MODE_SEL_NEW
);
135 if (!sunxi_mmc_can_calibrate()) {
137 * Use hardcoded delay values if controller doesn't support
140 val
= CCM_MMC_CTRL_OCLK_DLY(oclk_dly
) |
141 CCM_MMC_CTRL_SCLK_DLY(sclk_dly
);
144 writel(CCM_MMC_CTRL_ENABLE
| pll
| CCM_MMC_CTRL_N(n
) |
145 CCM_MMC_CTRL_M(div
) | val
, priv
->mclkreg
);
147 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
148 priv
->mmc_no
, hz
, pll_hz
, 1u << n
, div
, pll_hz
/ (1u << n
) / div
);
153 static int mmc_update_clk(struct sunxi_mmc_priv
*priv
)
156 unsigned timeout_msecs
= 2000;
157 unsigned long start
= get_timer(0);
159 cmd
= SUNXI_MMC_CMD_START
|
160 SUNXI_MMC_CMD_UPCLK_ONLY
|
161 SUNXI_MMC_CMD_WAIT_PRE_OVER
;
163 writel(cmd
, &priv
->reg
->cmd
);
164 while (readl(&priv
->reg
->cmd
) & SUNXI_MMC_CMD_START
) {
165 if (get_timer(start
) > timeout_msecs
)
169 /* clock update sets various irq status bits, clear these */
170 writel(readl(&priv
->reg
->rint
), &priv
->reg
->rint
);
175 static int mmc_config_clock(struct sunxi_mmc_priv
*priv
, struct mmc
*mmc
)
177 unsigned rval
= readl(&priv
->reg
->clkcr
);
180 rval
&= ~SUNXI_MMC_CLK_ENABLE
;
181 writel(rval
, &priv
->reg
->clkcr
);
182 if (mmc_update_clk(priv
))
185 /* Set mod_clk to new rate */
186 if (mmc_set_mod_clk(priv
, mmc
->clock
))
189 /* Clear internal divider */
190 rval
&= ~SUNXI_MMC_CLK_DIVIDER_MASK
;
191 writel(rval
, &priv
->reg
->clkcr
);
193 #if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6)
194 /* A64 supports calibration of delays on MMC controller and we
195 * have to set delay of zero before starting calibration.
196 * Allwinner BSP driver sets a delay only in the case of
197 * using HS400 which is not supported by mainline U-Boot or
198 * Linux at the moment
200 if (sunxi_mmc_can_calibrate())
201 writel(SUNXI_MMC_CAL_DL_SW_EN
, &priv
->reg
->samp_dl
);
204 /* Re-enable Clock */
205 rval
|= SUNXI_MMC_CLK_ENABLE
;
206 writel(rval
, &priv
->reg
->clkcr
);
207 if (mmc_update_clk(priv
))
213 static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv
*priv
,
216 debug("set ios: bus_width: %x, clock: %d\n",
217 mmc
->bus_width
, mmc
->clock
);
219 /* Change clock first */
220 if (mmc
->clock
&& mmc_config_clock(priv
, mmc
) != 0) {
225 /* Change bus width */
226 if (mmc
->bus_width
== 8)
227 writel(0x2, &priv
->reg
->width
);
228 else if (mmc
->bus_width
== 4)
229 writel(0x1, &priv
->reg
->width
);
231 writel(0x0, &priv
->reg
->width
);
236 static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv
*priv
, struct mmc
*mmc
,
237 struct mmc_data
*data
)
239 const int reading
= !!(data
->flags
& MMC_DATA_READ
);
240 const uint32_t status_bit
= reading
? SUNXI_MMC_STATUS_FIFO_EMPTY
:
241 SUNXI_MMC_STATUS_FIFO_FULL
;
243 unsigned *buff
= (unsigned int *)(reading
? data
->dest
: data
->src
);
244 unsigned word_cnt
= (data
->blocksize
* data
->blocks
) >> 2;
245 unsigned timeout_msecs
= word_cnt
>> 6;
249 if (timeout_msecs
< 2000)
250 timeout_msecs
= 2000;
252 /* Always read / write data through the CPU */
253 setbits_le32(&priv
->reg
->gctrl
, SUNXI_MMC_GCTRL_ACCESS_BY_AHB
);
255 start
= get_timer(0);
257 for (i
= 0; i
< word_cnt
;) {
258 unsigned int in_fifo
;
260 while ((status
= readl(&priv
->reg
->status
)) & status_bit
) {
261 if (get_timer(start
) > timeout_msecs
)
266 * For writing we do not easily know the FIFO size, so have
267 * to check the FIFO status after every word written.
268 * TODO: For optimisation we could work out a minimum FIFO
269 * size across all SoCs, and use that together with the current
270 * fill level to write chunks of words.
273 writel(buff
[i
++], &priv
->reg
->fifo
);
278 * The status register holds the current FIFO level, so we
279 * can be sure to collect as many words from the FIFO
280 * register without checking the status register after every
281 * read. That saves half of the costly MMIO reads, effectively
282 * doubling the read performance.
283 * Some SoCs (A20) report a level of 0 if the FIFO is
284 * completely full (value masked out?). Use a safe minimal
285 * FIFO size in this case.
287 in_fifo
= SUNXI_MMC_STATUS_FIFO_LEVEL(status
);
288 if (in_fifo
== 0 && (status
& SUNXI_MMC_STATUS_FIFO_FULL
))
290 for (; in_fifo
> 0; in_fifo
--)
291 buff
[i
++] = readl_relaxed(&priv
->reg
->fifo
);
298 static int mmc_rint_wait(struct sunxi_mmc_priv
*priv
, struct mmc
*mmc
,
299 uint timeout_msecs
, uint done_bit
, const char *what
)
302 unsigned long start
= get_timer(0);
305 status
= readl(&priv
->reg
->rint
);
306 if ((get_timer(start
) > timeout_msecs
) ||
307 (status
& SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT
)) {
308 debug("%s timeout %x\n", what
,
309 status
& SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT
);
312 } while (!(status
& done_bit
));
317 static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv
*priv
,
318 struct mmc
*mmc
, struct mmc_cmd
*cmd
,
319 struct mmc_data
*data
)
321 unsigned int cmdval
= SUNXI_MMC_CMD_START
;
322 unsigned int timeout_msecs
;
324 unsigned int status
= 0;
325 unsigned int bytecnt
= 0;
329 if (cmd
->resp_type
& MMC_RSP_BUSY
)
330 debug("mmc cmd %d check rsp busy\n", cmd
->cmdidx
);
331 if (cmd
->cmdidx
== 12)
335 cmdval
|= SUNXI_MMC_CMD_SEND_INIT_SEQ
;
336 if (cmd
->resp_type
& MMC_RSP_PRESENT
)
337 cmdval
|= SUNXI_MMC_CMD_RESP_EXPIRE
;
338 if (cmd
->resp_type
& MMC_RSP_136
)
339 cmdval
|= SUNXI_MMC_CMD_LONG_RESPONSE
;
340 if (cmd
->resp_type
& MMC_RSP_CRC
)
341 cmdval
|= SUNXI_MMC_CMD_CHK_RESPONSE_CRC
;
344 if ((u32
)(long)data
->dest
& 0x3) {
349 cmdval
|= SUNXI_MMC_CMD_DATA_EXPIRE
|SUNXI_MMC_CMD_WAIT_PRE_OVER
;
350 if (data
->flags
& MMC_DATA_WRITE
)
351 cmdval
|= SUNXI_MMC_CMD_WRITE
;
352 if (data
->blocks
> 1)
353 cmdval
|= SUNXI_MMC_CMD_AUTO_STOP
;
354 writel(data
->blocksize
, &priv
->reg
->blksz
);
355 writel(data
->blocks
* data
->blocksize
, &priv
->reg
->bytecnt
);
358 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv
->mmc_no
,
359 cmd
->cmdidx
, cmdval
| cmd
->cmdidx
, cmd
->cmdarg
);
360 writel(cmd
->cmdarg
, &priv
->reg
->arg
);
363 writel(cmdval
| cmd
->cmdidx
, &priv
->reg
->cmd
);
366 * transfer data and check status
367 * STATREG[2] : FIFO empty
368 * STATREG[3] : FIFO full
373 bytecnt
= data
->blocksize
* data
->blocks
;
374 debug("trans data %d bytes\n", bytecnt
);
375 writel(cmdval
| cmd
->cmdidx
, &priv
->reg
->cmd
);
376 ret
= mmc_trans_data_by_cpu(priv
, mmc
, data
);
378 error
= readl(&priv
->reg
->rint
) &
379 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT
;
385 error
= mmc_rint_wait(priv
, mmc
, 1000, SUNXI_MMC_RINT_COMMAND_DONE
,
392 debug("cacl timeout %x msec\n", timeout_msecs
);
393 error
= mmc_rint_wait(priv
, mmc
, timeout_msecs
,
395 SUNXI_MMC_RINT_AUTO_COMMAND_DONE
:
396 SUNXI_MMC_RINT_DATA_OVER
,
402 if (cmd
->resp_type
& MMC_RSP_BUSY
) {
403 unsigned long start
= get_timer(0);
404 timeout_msecs
= 2000;
407 status
= readl(&priv
->reg
->status
);
408 if (get_timer(start
) > timeout_msecs
) {
409 debug("busy timeout\n");
413 } while (status
& SUNXI_MMC_STATUS_CARD_DATA_BUSY
);
416 if (cmd
->resp_type
& MMC_RSP_136
) {
417 cmd
->response
[0] = readl(&priv
->reg
->resp3
);
418 cmd
->response
[1] = readl(&priv
->reg
->resp2
);
419 cmd
->response
[2] = readl(&priv
->reg
->resp1
);
420 cmd
->response
[3] = readl(&priv
->reg
->resp0
);
421 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
422 cmd
->response
[3], cmd
->response
[2],
423 cmd
->response
[1], cmd
->response
[0]);
425 cmd
->response
[0] = readl(&priv
->reg
->resp0
);
426 debug("mmc resp 0x%08x\n", cmd
->response
[0]);
430 writel(SUNXI_MMC_GCTRL_RESET
, &priv
->reg
->gctrl
);
431 mmc_update_clk(priv
);
433 writel(0xffffffff, &priv
->reg
->rint
);
434 writel(readl(&priv
->reg
->gctrl
) | SUNXI_MMC_GCTRL_FIFO_RESET
,
440 /* non-DM code here is used by the (ARM) SPL only */
442 #if !CONFIG_IS_ENABLED(DM_MMC)
443 /* support 4 mmc hosts */
444 struct sunxi_mmc_priv mmc_host
[4];
446 static int mmc_resource_init(int sdc_no
)
448 struct sunxi_mmc_priv
*priv
= &mmc_host
[sdc_no
];
449 struct sunxi_ccm_reg
*ccm
= (struct sunxi_ccm_reg
*)SUNXI_CCM_BASE
;
451 debug("init mmc %d resource\n", sdc_no
);
455 priv
->reg
= (struct sunxi_mmc
*)SUNXI_MMC0_BASE
;
456 priv
->mclkreg
= &ccm
->sd0_clk_cfg
;
459 priv
->reg
= (struct sunxi_mmc
*)SUNXI_MMC1_BASE
;
460 priv
->mclkreg
= &ccm
->sd1_clk_cfg
;
462 #ifdef SUNXI_MMC2_BASE
464 priv
->reg
= (struct sunxi_mmc
*)SUNXI_MMC2_BASE
;
465 priv
->mclkreg
= &ccm
->sd2_clk_cfg
;
468 #ifdef SUNXI_MMC3_BASE
470 priv
->reg
= (struct sunxi_mmc
*)SUNXI_MMC3_BASE
;
471 priv
->mclkreg
= &ccm
->sd3_clk_cfg
;
475 printf("Wrong mmc number %d\n", sdc_no
);
478 priv
->mmc_no
= sdc_no
;
483 static int sunxi_mmc_core_init(struct mmc
*mmc
)
485 struct sunxi_mmc_priv
*priv
= mmc
->priv
;
487 /* Reset controller */
488 writel(SUNXI_MMC_GCTRL_RESET
, &priv
->reg
->gctrl
);
494 static int sunxi_mmc_set_ios_legacy(struct mmc
*mmc
)
496 struct sunxi_mmc_priv
*priv
= mmc
->priv
;
498 return sunxi_mmc_set_ios_common(priv
, mmc
);
501 static int sunxi_mmc_send_cmd_legacy(struct mmc
*mmc
, struct mmc_cmd
*cmd
,
502 struct mmc_data
*data
)
504 struct sunxi_mmc_priv
*priv
= mmc
->priv
;
506 return sunxi_mmc_send_cmd_common(priv
, mmc
, cmd
, data
);
509 /* .getcd is not needed by the SPL */
510 static const struct mmc_ops sunxi_mmc_ops
= {
511 .send_cmd
= sunxi_mmc_send_cmd_legacy
,
512 .set_ios
= sunxi_mmc_set_ios_legacy
,
513 .init
= sunxi_mmc_core_init
,
516 struct mmc
*sunxi_mmc_init(int sdc_no
)
518 struct sunxi_ccm_reg
*ccm
= (struct sunxi_ccm_reg
*)SUNXI_CCM_BASE
;
519 struct sunxi_mmc_priv
*priv
= &mmc_host
[sdc_no
];
520 struct mmc_config
*cfg
= &priv
->cfg
;
523 memset(priv
, '\0', sizeof(struct sunxi_mmc_priv
));
525 cfg
->name
= "SUNXI SD/MMC";
526 cfg
->ops
= &sunxi_mmc_ops
;
528 cfg
->voltages
= MMC_VDD_32_33
| MMC_VDD_33_34
;
529 cfg
->host_caps
= MMC_MODE_4BIT
;
531 if ((IS_ENABLED(CONFIG_MACH_SUN50I
) || IS_ENABLED(CONFIG_MACH_SUN8I
) ||
532 IS_ENABLED(CONFIG_SUN50I_GEN_H6
)) && (sdc_no
== 2))
533 cfg
->host_caps
= MMC_MODE_8BIT
;
535 cfg
->host_caps
|= MMC_MODE_HS_52MHz
| MMC_MODE_HS
;
536 cfg
->b_max
= CONFIG_SYS_MMC_MAX_BLK_COUNT
;
539 cfg
->f_max
= 52000000;
541 if (mmc_resource_init(sdc_no
) != 0)
544 /* config ahb clock */
545 debug("init mmc %d clock and io\n", sdc_no
);
546 #if !defined(CONFIG_SUN50I_GEN_H6)
547 setbits_le32(&ccm
->ahb_gate0
, 1 << AHB_GATE_OFFSET_MMC(sdc_no
));
549 #ifdef CONFIG_SUNXI_GEN_SUN6I
551 setbits_le32(&ccm
->ahb_reset0_cfg
, 1 << AHB_RESET_OFFSET_MMC(sdc_no
));
553 #if defined(CONFIG_MACH_SUN9I)
554 /* sun9i has a mmc-common module, also set the gate and reset there */
555 writel(SUNXI_MMC_COMMON_CLK_GATE
| SUNXI_MMC_COMMON_RESET
,
556 SUNXI_MMC_COMMON_BASE
+ 4 * sdc_no
);
558 #else /* CONFIG_SUN50I_GEN_H6 */
559 setbits_le32(&ccm
->sd_gate_reset
, 1 << sdc_no
);
561 setbits_le32(&ccm
->sd_gate_reset
, 1 << (RESET_SHIFT
+ sdc_no
));
563 ret
= mmc_set_mod_clk(priv
, 24000000);
567 return mmc_create(cfg
, priv
);
570 #else /* CONFIG_DM_MMC code below, as used by U-Boot proper */
572 static int sunxi_mmc_set_ios(struct udevice
*dev
)
574 struct sunxi_mmc_plat
*plat
= dev_get_plat(dev
);
575 struct sunxi_mmc_priv
*priv
= dev_get_priv(dev
);
577 return sunxi_mmc_set_ios_common(priv
, &plat
->mmc
);
580 static int sunxi_mmc_send_cmd(struct udevice
*dev
, struct mmc_cmd
*cmd
,
581 struct mmc_data
*data
)
583 struct sunxi_mmc_plat
*plat
= dev_get_plat(dev
);
584 struct sunxi_mmc_priv
*priv
= dev_get_priv(dev
);
586 return sunxi_mmc_send_cmd_common(priv
, &plat
->mmc
, cmd
, data
);
589 static int sunxi_mmc_getcd(struct udevice
*dev
)
591 struct mmc
*mmc
= mmc_get_mmc_dev(dev
);
592 struct sunxi_mmc_priv
*priv
= dev_get_priv(dev
);
594 /* If polling, assume that the card is always present. */
595 if ((mmc
->cfg
->host_caps
& MMC_CAP_NONREMOVABLE
) ||
596 (mmc
->cfg
->host_caps
& MMC_CAP_NEEDS_POLL
))
599 if (dm_gpio_is_valid(&priv
->cd_gpio
)) {
600 int cd_state
= dm_gpio_get_value(&priv
->cd_gpio
);
602 if (mmc
->cfg
->host_caps
& MMC_CAP_CD_ACTIVE_HIGH
)
610 static const struct dm_mmc_ops sunxi_mmc_ops
= {
611 .send_cmd
= sunxi_mmc_send_cmd
,
612 .set_ios
= sunxi_mmc_set_ios
,
613 .get_cd
= sunxi_mmc_getcd
,
616 static unsigned get_mclk_offset(void)
618 if (IS_ENABLED(CONFIG_MACH_SUN9I_A80
))
621 if (IS_ENABLED(CONFIG_SUN50I_GEN_H6
))
627 static int sunxi_mmc_probe(struct udevice
*dev
)
629 struct mmc_uclass_priv
*upriv
= dev_get_uclass_priv(dev
);
630 struct sunxi_mmc_plat
*plat
= dev_get_plat(dev
);
631 struct sunxi_mmc_priv
*priv
= dev_get_priv(dev
);
632 struct reset_ctl_bulk reset_bulk
;
634 struct mmc_config
*cfg
= &plat
->cfg
;
635 struct ofnode_phandle_args args
;
639 cfg
->name
= dev
->name
;
641 cfg
->voltages
= MMC_VDD_32_33
| MMC_VDD_33_34
;
642 cfg
->host_caps
= MMC_MODE_HS_52MHz
| MMC_MODE_HS
;
643 cfg
->b_max
= CONFIG_SYS_MMC_MAX_BLK_COUNT
;
646 cfg
->f_max
= 52000000;
648 ret
= mmc_of_parse(dev
, cfg
);
652 priv
->reg
= dev_read_addr_ptr(dev
);
654 /* We don't have a sunxi clock driver so find the clock address here */
655 ret
= dev_read_phandle_with_args(dev
, "clocks", "#clock-cells", 0,
659 ccu_reg
= (u32
*)(uintptr_t)ofnode_get_addr(args
.node
);
661 priv
->mmc_no
= ((uintptr_t)priv
->reg
- SUNXI_MMC0_BASE
) / 0x1000;
662 priv
->mclkreg
= (void *)ccu_reg
+ get_mclk_offset() + priv
->mmc_no
* 4;
664 ret
= clk_get_by_name(dev
, "ahb", &gate_clk
);
666 clk_enable(&gate_clk
);
668 ret
= reset_get_bulk(dev
, &reset_bulk
);
670 reset_deassert_bulk(&reset_bulk
);
672 ret
= mmc_set_mod_clk(priv
, 24000000);
676 /* This GPIO is optional */
677 gpio_request_by_name(dev
, "cd-gpios", 0, &priv
->cd_gpio
,
678 GPIOD_IS_IN
| GPIOD_PULL_UP
);
680 upriv
->mmc
= &plat
->mmc
;
682 /* Reset controller */
683 writel(SUNXI_MMC_GCTRL_RESET
, &priv
->reg
->gctrl
);
689 static int sunxi_mmc_bind(struct udevice
*dev
)
691 struct sunxi_mmc_plat
*plat
= dev_get_plat(dev
);
693 return mmc_bind(dev
, &plat
->mmc
, &plat
->cfg
);
696 static const struct udevice_id sunxi_mmc_ids
[] = {
697 { .compatible
= "allwinner,sun4i-a10-mmc" },
698 { .compatible
= "allwinner,sun5i-a13-mmc" },
699 { .compatible
= "allwinner,sun7i-a20-mmc" },
700 { .compatible
= "allwinner,sun8i-a83t-emmc" },
701 { .compatible
= "allwinner,sun9i-a80-mmc" },
702 { .compatible
= "allwinner,sun50i-a64-mmc" },
703 { .compatible
= "allwinner,sun50i-a64-emmc" },
704 { .compatible
= "allwinner,sun50i-h6-mmc" },
705 { .compatible
= "allwinner,sun50i-h6-emmc" },
706 { .compatible
= "allwinner,sun50i-a100-mmc" },
707 { .compatible
= "allwinner,sun50i-a100-emmc" },
711 U_BOOT_DRIVER(sunxi_mmc_drv
) = {
714 .of_match
= sunxi_mmc_ids
,
715 .bind
= sunxi_mmc_bind
,
716 .probe
= sunxi_mmc_probe
,
717 .ops
= &sunxi_mmc_ops
,
718 .plat_auto
= sizeof(struct sunxi_mmc_plat
),
719 .priv_auto
= sizeof(struct sunxi_mmc_priv
),