]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/mmc/gen_atmel_mci.c
Merge git://git.denx.de/u-boot-mmc
[people/ms/u-boot.git] / drivers / mmc / gen_atmel_mci.c
CommitLineData
1592ef85
RM
1/*
2 * Copyright (C) 2010
3 * Rob Emanuele <rob@emanuele.us>
4 * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
5 *
6 * Original Driver:
7 * Copyright (C) 2004-2006 Atmel Corporation
8 *
1a459660 9 * SPDX-License-Identifier: GPL-2.0+
1592ef85
RM
10 */
11
12#include <common.h>
c86c0155 13#include <clk.h>
9d922450 14#include <dm.h>
1592ef85
RM
15#include <mmc.h>
16#include <part.h>
17#include <malloc.h>
18#include <asm/io.h>
1221ce45 19#include <linux/errno.h>
1592ef85
RM
20#include <asm/byteorder.h>
21#include <asm/arch/clk.h>
329f0f52 22#include <asm/arch/hardware.h>
1592ef85
RM
23#include "atmel_mci.h"
24
c86c0155
WY
25DECLARE_GLOBAL_DATA_PTR;
26
1592ef85
RM
27#ifndef CONFIG_SYS_MMC_CLK_OD
28# define CONFIG_SYS_MMC_CLK_OD 150000
29#endif
30
31#define MMC_DEFAULT_BLKLEN 512
32
33#if defined(CONFIG_ATMEL_MCI_PORTB)
34# define MCI_BUS 1
35#else
36# define MCI_BUS 0
37#endif
38
722b150e
WY
39#ifdef CONFIG_DM_MMC
40struct atmel_mci_plat {
41 struct mmc mmc;
42 struct mmc_config cfg;
43 struct atmel_mci *mci;
44};
45#endif
46
6b75d359 47struct atmel_mci_priv {
722b150e 48#ifndef CONFIG_DM_MMC
6b75d359
MV
49 struct mmc_config cfg;
50 struct atmel_mci *mci;
722b150e 51#endif
877807e1 52 unsigned int initialized:1;
b4670a0c 53 unsigned int curr_clk;
c86c0155 54#ifdef CONFIG_DM_MMC
c86c0155
WY
55 ulong bus_clk_rate;
56#endif
6b75d359
MV
57};
58
aac4b69b
BS
59/* Read Atmel MCI IP version */
60static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
61{
62 return readl(&mci->version) & 0x00000fff;
63}
64
1592ef85
RM
65/*
66 * Print command and status:
67 *
68 * - always when DEBUG is defined
69 * - on command errors
70 */
71static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
72{
b84c9c9a
MV
73 debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
74 cmdr, cmdr & 0x3F, arg, status, msg);
1592ef85
RM
75}
76
9b79dbd2
JJH
77static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
78{
79 unsigned int version = atmel_mci_get_version(mci);
80
81 blklen &= 0xfffc;
82
83 /* MCI IP version >= 0x200 has blkr */
84 if (version >= 0x200)
85 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
86 &mci->blkr);
87 else
88 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
89}
90
1592ef85 91/* Setup for MCI Clock and Block Size */
c86c0155 92#ifdef CONFIG_DM_MMC
722b150e 93static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
c86c0155 94{
722b150e
WY
95 struct atmel_mci_plat *plat = dev_get_platdata(dev);
96 struct atmel_mci_priv *priv = dev_get_priv(dev);
97 struct mmc *mmc = &plat->mmc;
c86c0155 98 u32 bus_hz = priv->bus_clk_rate;
722b150e 99 atmel_mci_t *mci = plat->mci;
c86c0155 100#else
1592ef85
RM
101static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
102{
6b75d359 103 struct atmel_mci_priv *priv = mmc->priv;
1592ef85 104 u32 bus_hz = get_mci_clk_rate();
722b150e 105 atmel_mci_t *mci = priv->mci;
c86c0155
WY
106#endif
107
1592ef85 108 u32 clkdiv = 255;
cd60ebd4
BS
109 unsigned int version = atmel_mci_get_version(mci);
110 u32 clkodd = 0;
111 u32 mr;
1592ef85
RM
112
113 debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
114 bus_hz, hz, blklen);
115 if (hz > 0) {
cd60ebd4
BS
116 if (version >= 0x500) {
117 clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
118 if (clkdiv > 511)
119 clkdiv = 511;
120
121 clkodd = clkdiv & 1;
122 clkdiv >>= 1;
123
b84c9c9a
MV
124 debug("mci: setting clock %u Hz, block size %u\n",
125 bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
cd60ebd4
BS
126 } else {
127 /* find clkdiv yielding a rate <= than requested */
128 for (clkdiv = 0; clkdiv < 255; clkdiv++) {
129 if ((bus_hz / (clkdiv + 1) / 2) <= hz)
130 break;
131 }
b84c9c9a
MV
132 debug("mci: setting clock %u Hz, block size %u\n",
133 (bus_hz / (clkdiv + 1)) / 2, blklen);
cd60ebd4 134
1592ef85
RM
135 }
136 }
b4670a0c
GC
137 if (version >= 0x500)
138 priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
139 else
140 priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
cd60ebd4
BS
141
142 mr = MMCI_BF(CLKDIV, clkdiv);
143
144 /* MCI IP version >= 0x200 has R/WPROOF */
145 if (version >= 0x200)
146 mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
147
1db7377a 148 /*
cd60ebd4
BS
149 * MCI IP version >= 0x500 use bit 16 as clkodd.
150 * MCI IP version < 0x500 use upper 16 bits for blklen.
1db7377a 151 */
cd60ebd4
BS
152 if (version >= 0x500)
153 mr |= MMCI_BF(CLKODD, clkodd);
cd60ebd4
BS
154
155 writel(mr, &mci->mr);
156
9b79dbd2 157 mci_set_blklen(mci, blklen);
cd60ebd4 158
da55c66e
BS
159 if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
160 writel(MMCI_BIT(HSMODE), &mci->cfg);
161
877807e1 162 priv->initialized = 1;
1592ef85
RM
163}
164
165/* Return the CMDR with flags for a given command and data packet */
166static u32 mci_encode_cmd(
167 struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
168{
169 u32 cmdr = 0;
170
171 /* Default Flags for Errors */
172 *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
173 MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
174
175 /* Default Flags for the Command */
176 cmdr |= MMCI_BIT(MAXLAT);
177
178 if (data) {
179 cmdr |= MMCI_BF(TRCMD, 1);
180 if (data->blocks > 1)
181 cmdr |= MMCI_BF(TRTYP, 1);
182 if (data->flags & MMC_DATA_READ)
183 cmdr |= MMCI_BIT(TRDIR);
184 }
185
186 if (cmd->resp_type & MMC_RSP_CRC)
187 *error_flags |= MMCI_BIT(RCRCE);
188 if (cmd->resp_type & MMC_RSP_136)
189 cmdr |= MMCI_BF(RSPTYP, 2);
190 else if (cmd->resp_type & MMC_RSP_BUSY)
191 cmdr |= MMCI_BF(RSPTYP, 3);
192 else if (cmd->resp_type & MMC_RSP_PRESENT)
193 cmdr |= MMCI_BF(RSPTYP, 1);
194
195 return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
196}
197
198/* Entered into function pointer in mci_send_cmd */
199static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
200{
201 u32 status;
202
203 do {
204 status = readl(&mci->sr);
205 if (status & (error_flags | MMCI_BIT(OVRE)))
206 goto io_fail;
207 } while (!(status & MMCI_BIT(RXRDY)));
208
209 if (status & MMCI_BIT(RXRDY)) {
210 *data = readl(&mci->rdr);
211 status = 0;
212 }
213io_fail:
214 return status;
215}
216
217/* Entered into function pointer in mci_send_cmd */
218static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
219{
220 u32 status;
221
222 do {
223 status = readl(&mci->sr);
224 if (status & (error_flags | MMCI_BIT(UNRE)))
225 goto io_fail;
226 } while (!(status & MMCI_BIT(TXRDY)));
227
228 if (status & MMCI_BIT(TXRDY)) {
229 writel(*data, &mci->tdr);
230 status = 0;
231 }
232io_fail:
233 return status;
234}
235
236/*
237 * Entered into mmc structure during driver init
238 *
239 * Sends a command out on the bus and deals with the block data.
240 * Takes the mmc pointer, a command pointer, and an optional data pointer.
241 */
c86c0155
WY
242#ifdef CONFIG_DM_MMC
243static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
244 struct mmc_data *data)
245{
722b150e 246 struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155 247 struct atmel_mci_priv *priv = dev_get_priv(dev);
722b150e 248 atmel_mci_t *mci = plat->mci;
c86c0155 249#else
1592ef85
RM
250static int
251mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
252{
6b75d359
MV
253 struct atmel_mci_priv *priv = mmc->priv;
254 atmel_mci_t *mci = priv->mci;
722b150e 255#endif
1592ef85
RM
256 u32 cmdr;
257 u32 error_flags = 0;
258 u32 status;
259
877807e1 260 if (!priv->initialized) {
1592ef85 261 puts ("MCI not initialized!\n");
915ffa52 262 return -ECOMM;
1592ef85
RM
263 }
264
265 /* Figure out the transfer arguments */
266 cmdr = mci_encode_cmd(cmd, data, &error_flags);
267
9b79dbd2
JJH
268 mci_set_blklen(mci, data->blocksize);
269
1db7377a
WJ
270 /* For multi blocks read/write, set the block register */
271 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
272 || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
9b79dbd2
JJH
273 writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
274 &mci->blkr);
1db7377a 275
1592ef85
RM
276 /* Send the command */
277 writel(cmd->cmdarg, &mci->argr);
278 writel(cmdr, &mci->cmdr);
279
280#ifdef DEBUG
281 dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
282#endif
283
284 /* Wait for the command to complete */
285 while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
286
93e3236c
BS
287 if ((status & error_flags) & MMCI_BIT(RTOE)) {
288 dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
915ffa52 289 return -ETIMEDOUT;
93e3236c 290 } else if (status & error_flags) {
1592ef85 291 dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
915ffa52 292 return -ECOMM;
1592ef85
RM
293 }
294
295 /* Copy the response to the response buffer */
296 if (cmd->resp_type & MMC_RSP_136) {
297 cmd->response[0] = readl(&mci->rspr);
298 cmd->response[1] = readl(&mci->rspr1);
299 cmd->response[2] = readl(&mci->rspr2);
300 cmd->response[3] = readl(&mci->rspr3);
301 } else
302 cmd->response[0] = readl(&mci->rspr);
303
304 /* transfer all of the blocks */
305 if (data) {
306 u32 word_count, block_count;
307 u32* ioptr;
9b79dbd2 308 u32 i;
1592ef85
RM
309 u32 (*mci_data_op)
310 (atmel_mci_t *mci, u32* data, u32 error_flags);
311
312 if (data->flags & MMC_DATA_READ) {
313 mci_data_op = mci_data_read;
1592ef85
RM
314 ioptr = (u32*)data->dest;
315 } else {
316 mci_data_op = mci_data_write;
1592ef85
RM
317 ioptr = (u32*)data->src;
318 }
319
320 status = 0;
321 for (block_count = 0;
322 block_count < data->blocks && !status;
323 block_count++) {
324 word_count = 0;
325 do {
326 status = mci_data_op(mci, ioptr, error_flags);
327 word_count++;
328 ioptr++;
329 } while (!status && word_count < (data->blocksize/4));
330#ifdef DEBUG
331 if (data->flags & MMC_DATA_READ)
332 {
9902c7b6 333 u32 cnt = word_count * 4;
1592ef85 334 printf("Read Data:\n");
9902c7b6
WJ
335 print_buffer(0, data->dest + cnt * block_count,
336 1, cnt, 0);
1592ef85
RM
337 }
338#endif
1592ef85
RM
339 if (status) {
340 dump_cmd(cmdr, cmd->cmdarg, status,
341 "Data Transfer Failed");
915ffa52 342 return -ECOMM;
1592ef85
RM
343 }
344 }
345
346 /* Wait for Transfer End */
347 i = 0;
348 do {
349 status = readl(&mci->sr);
350
351 if (status & error_flags) {
352 dump_cmd(cmdr, cmd->cmdarg, status,
353 "DTIP Wait Failed");
915ffa52 354 return -ECOMM;
1592ef85
RM
355 }
356 i++;
357 } while ((status & MMCI_BIT(DTIP)) && i < 10000);
358 if (status & MMCI_BIT(DTIP)) {
359 dump_cmd(cmdr, cmd->cmdarg, status,
360 "XFER DTIP never unset, ignoring");
361 }
362 }
363
b4670a0c
GC
364 /*
365 * After the switch command, wait for 8 clocks before the next
366 * command
367 */
368 if (cmd->cmdidx == MMC_CMD_SWITCH)
369 udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
370
1592ef85
RM
371 return 0;
372}
373
c86c0155
WY
374#ifdef CONFIG_DM_MMC
375static int atmel_mci_set_ios(struct udevice *dev)
376{
722b150e 377 struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155 378 struct mmc *mmc = mmc_get_mmc_dev(dev);
722b150e 379 atmel_mci_t *mci = plat->mci;
c86c0155 380#else
1592ef85 381/* Entered into mmc structure during driver init */
07b0b9c0 382static int mci_set_ios(struct mmc *mmc)
1592ef85 383{
6b75d359
MV
384 struct atmel_mci_priv *priv = mmc->priv;
385 atmel_mci_t *mci = priv->mci;
722b150e 386#endif
aac4b69b
BS
387 int bus_width = mmc->bus_width;
388 unsigned int version = atmel_mci_get_version(mci);
389 int busw;
1592ef85
RM
390
391 /* Set the clock speed */
c86c0155 392#ifdef CONFIG_DM_MMC
722b150e 393 mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
c86c0155 394#else
1592ef85 395 mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
c86c0155 396#endif
1592ef85
RM
397
398 /*
399 * set the bus width and select slot for this interface
400 * there is no capability for multiple slots on the same interface yet
1592ef85 401 */
aac4b69b
BS
402 if ((version & 0xf00) >= 0x300) {
403 switch (bus_width) {
404 case 8:
405 busw = 3;
406 break;
407 case 4:
408 busw = 2;
409 break;
410 default:
411 busw = 0;
412 break;
413 }
414
415 writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
416 } else {
417 busw = (bus_width == 4) ? 1 : 0;
418
419 writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
420 }
07b0b9c0
JC
421
422 return 0;
1592ef85
RM
423}
424
c86c0155 425#ifdef CONFIG_DM_MMC
722b150e 426static int atmel_mci_hw_init(struct udevice *dev)
c86c0155 427{
722b150e
WY
428 struct atmel_mci_plat *plat = dev_get_platdata(dev);
429 atmel_mci_t *mci = plat->mci;
c86c0155 430#else
1592ef85
RM
431/* Entered into mmc structure during driver init */
432static int mci_init(struct mmc *mmc)
433{
6b75d359
MV
434 struct atmel_mci_priv *priv = mmc->priv;
435 atmel_mci_t *mci = priv->mci;
722b150e 436#endif
1592ef85
RM
437
438 /* Initialize controller */
439 writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
440 writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */
441 writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */
2aed9d14 442 writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */
1592ef85 443
9924ca6e
WJ
444 /* This delay can be optimized, but stick with max value */
445 writel(0x7f, &mci->dtor);
1592ef85
RM
446 /* Disable Interrupts */
447 writel(~0UL, &mci->idr);
448
449 /* Set default clocks and blocklen */
c86c0155 450#ifdef CONFIG_DM_MMC
722b150e 451 mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
c86c0155 452#else
1592ef85 453 mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
c86c0155 454#endif
1592ef85
RM
455
456 return 0;
457}
458
c86c0155 459#ifndef CONFIG_DM_MMC
ab769f22
PA
460static const struct mmc_ops atmel_mci_ops = {
461 .send_cmd = mci_send_cmd,
462 .set_ios = mci_set_ios,
463 .init = mci_init,
464};
465
1592ef85
RM
466/*
467 * This is the only exported function
468 *
469 * Call it with the MCI register base address
470 */
471int atmel_mci_init(void *regs)
472{
93bfd616
PA
473 struct mmc *mmc;
474 struct mmc_config *cfg;
6b75d359 475 struct atmel_mci_priv *priv;
aac4b69b 476 unsigned int version;
1592ef85 477
6b75d359
MV
478 priv = calloc(1, sizeof(*priv));
479 if (!priv)
480 return -ENOMEM;
aac4b69b 481
6b75d359 482 cfg = &priv->cfg;
93bfd616
PA
483
484 cfg->name = "mci";
485 cfg->ops = &atmel_mci_ops;
1592ef85 486
6b75d359 487 priv->mci = (struct atmel_mci *)regs;
877807e1 488 priv->initialized = 0;
6b75d359 489
1592ef85 490 /* need to be able to pass these in on a board by board basis */
93bfd616 491 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
6b75d359 492 version = atmel_mci_get_version(priv->mci);
da55c66e 493 if ((version & 0xf00) >= 0x300) {
93bfd616 494 cfg->host_caps = MMC_MODE_8BIT;
da55c66e
BS
495 cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
496 }
aac4b69b 497
93bfd616 498 cfg->host_caps |= MMC_MODE_4BIT;
aac4b69b 499
1592ef85
RM
500 /*
501 * min and max frequencies determined by
502 * max and min of clock divider
503 */
93bfd616
PA
504 cfg->f_min = get_mci_clk_rate() / (2*256);
505 cfg->f_max = get_mci_clk_rate() / (2*1);
506
507 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1592ef85 508
6b75d359 509 mmc = mmc_create(cfg, priv);
8feafcc4 510
93bfd616 511 if (mmc == NULL) {
6b75d359
MV
512 free(priv);
513 return -ENODEV;
93bfd616 514 }
6b75d359 515 /* NOTE: possibly leaking the priv structure */
1592ef85
RM
516
517 return 0;
518}
c86c0155
WY
519#endif
520
521#ifdef CONFIG_DM_MMC
522static const struct dm_mmc_ops atmel_mci_mmc_ops = {
523 .send_cmd = atmel_mci_send_cmd,
524 .set_ios = atmel_mci_set_ios,
525};
526
722b150e 527static void atmel_mci_setup_cfg(struct udevice *dev)
c86c0155 528{
722b150e
WY
529 struct atmel_mci_plat *plat = dev_get_platdata(dev);
530 struct atmel_mci_priv *priv = dev_get_priv(dev);
c86c0155
WY
531 struct mmc_config *cfg;
532 u32 version;
533
722b150e 534 cfg = &plat->cfg;
c86c0155
WY
535 cfg->name = "Atmel mci";
536 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
537
538 /*
539 * If the version is above 3.0, the capabilities of the 8-bit
540 * bus width and high speed are supported.
541 */
722b150e 542 version = atmel_mci_get_version(plat->mci);
c86c0155
WY
543 if ((version & 0xf00) >= 0x300) {
544 cfg->host_caps = MMC_MODE_8BIT |
545 MMC_MODE_HS | MMC_MODE_HS_52MHz;
546 }
547
548 cfg->host_caps |= MMC_MODE_4BIT;
549 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
550 cfg->f_min = priv->bus_clk_rate / (2 * 256);
551 cfg->f_max = priv->bus_clk_rate / 2;
552}
553
554static int atmel_mci_enable_clk(struct udevice *dev)
555{
556 struct atmel_mci_priv *priv = dev_get_priv(dev);
557 struct clk clk;
558 ulong clk_rate;
559 int ret = 0;
560
561 ret = clk_get_by_index(dev, 0, &clk);
562 if (ret) {
563 ret = -EINVAL;
564 goto failed;
565 }
566
567 ret = clk_enable(&clk);
568 if (ret)
569 goto failed;
570
571 clk_rate = clk_get_rate(&clk);
572 if (!clk_rate) {
573 ret = -EINVAL;
574 goto failed;
575 }
576
577 priv->bus_clk_rate = clk_rate;
578
579failed:
580 clk_free(&clk);
581
582 return ret;
583}
584
585static int atmel_mci_probe(struct udevice *dev)
586{
587 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
722b150e 588 struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155
WY
589 struct mmc *mmc;
590 int ret;
591
592 ret = atmel_mci_enable_clk(dev);
593 if (ret)
594 return ret;
595
722b150e 596 plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
c86c0155 597
722b150e 598 atmel_mci_setup_cfg(dev);
c86c0155 599
722b150e
WY
600 mmc = &plat->mmc;
601 mmc->cfg = &plat->cfg;
c86c0155
WY
602 mmc->dev = dev;
603 upriv->mmc = mmc;
604
722b150e 605 atmel_mci_hw_init(dev);
c86c0155
WY
606
607 return 0;
608}
609
610static int atmel_mci_bind(struct udevice *dev)
611{
722b150e 612 struct atmel_mci_plat *plat = dev_get_platdata(dev);
c86c0155 613
722b150e 614 return mmc_bind(dev, &plat->mmc, &plat->cfg);
c86c0155
WY
615}
616
617static const struct udevice_id atmel_mci_ids[] = {
618 { .compatible = "atmel,hsmci" },
619 { }
620};
621
622U_BOOT_DRIVER(atmel_mci) = {
623 .name = "atmel-mci",
624 .id = UCLASS_MMC,
625 .of_match = atmel_mci_ids,
626 .bind = atmel_mci_bind,
627 .probe = atmel_mci_probe,
722b150e 628 .platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
c86c0155
WY
629 .priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
630 .ops = &atmel_mci_mmc_ops,
631};
632#endif