1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Faraday MMC/SD Host Controller
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) Copyright 2010 Faraday Technology
5*4882a593Smuzhiyun * Dante Su <dantesu@faraday-tech.com>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun #include <part.h>
13*4882a593Smuzhiyun #include <mmc.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <asm/byteorder.h>
18*4882a593Smuzhiyun #include <faraday/ftsdc010.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
21*4882a593Smuzhiyun #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun struct ftsdc010_chip {
24*4882a593Smuzhiyun void __iomem *regs;
25*4882a593Smuzhiyun uint32_t wprot; /* write protected (locked) */
26*4882a593Smuzhiyun uint32_t rate; /* actual SD clock in Hz */
27*4882a593Smuzhiyun uint32_t sclk; /* FTSDC010 source clock in Hz */
28*4882a593Smuzhiyun uint32_t fifo; /* fifo depth in bytes */
29*4882a593Smuzhiyun uint32_t acmd;
30*4882a593Smuzhiyun struct mmc_config cfg; /* mmc configuration */
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
ftsdc010_send_cmd(struct mmc * mmc,struct mmc_cmd * mmc_cmd)33*4882a593Smuzhiyun static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct ftsdc010_chip *chip = mmc->priv;
36*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs = chip->regs;
37*4882a593Smuzhiyun int ret = -ETIMEDOUT;
38*4882a593Smuzhiyun uint32_t ts, st;
39*4882a593Smuzhiyun uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
40*4882a593Smuzhiyun uint32_t arg = mmc_cmd->cmdarg;
41*4882a593Smuzhiyun uint32_t flags = mmc_cmd->resp_type;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun cmd |= FTSDC010_CMD_CMD_EN;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun if (chip->acmd) {
46*4882a593Smuzhiyun cmd |= FTSDC010_CMD_APP_CMD;
47*4882a593Smuzhiyun chip->acmd = 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (flags & MMC_RSP_PRESENT)
51*4882a593Smuzhiyun cmd |= FTSDC010_CMD_NEED_RSP;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (flags & MMC_RSP_136)
54*4882a593Smuzhiyun cmd |= FTSDC010_CMD_LONG_RSP;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
57*4882a593Smuzhiyun ®s->clr);
58*4882a593Smuzhiyun writel(arg, ®s->argu);
59*4882a593Smuzhiyun writel(cmd, ®s->cmd);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
62*4882a593Smuzhiyun for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
63*4882a593Smuzhiyun if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) {
64*4882a593Smuzhiyun writel(FTSDC010_STATUS_CMD_SEND, ®s->clr);
65*4882a593Smuzhiyun ret = 0;
66*4882a593Smuzhiyun break;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun } else {
70*4882a593Smuzhiyun st = 0;
71*4882a593Smuzhiyun for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
72*4882a593Smuzhiyun st = readl(®s->status);
73*4882a593Smuzhiyun writel(st & FTSDC010_STATUS_RSP_MASK, ®s->clr);
74*4882a593Smuzhiyun if (st & FTSDC010_STATUS_RSP_MASK)
75*4882a593Smuzhiyun break;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun if (st & FTSDC010_STATUS_RSP_CRC_OK) {
78*4882a593Smuzhiyun if (flags & MMC_RSP_136) {
79*4882a593Smuzhiyun mmc_cmd->response[0] = readl(®s->rsp3);
80*4882a593Smuzhiyun mmc_cmd->response[1] = readl(®s->rsp2);
81*4882a593Smuzhiyun mmc_cmd->response[2] = readl(®s->rsp1);
82*4882a593Smuzhiyun mmc_cmd->response[3] = readl(®s->rsp0);
83*4882a593Smuzhiyun } else {
84*4882a593Smuzhiyun mmc_cmd->response[0] = readl(®s->rsp0);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun ret = 0;
87*4882a593Smuzhiyun } else {
88*4882a593Smuzhiyun debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
89*4882a593Smuzhiyun mmc_cmd->cmdidx, st);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (ret) {
94*4882a593Smuzhiyun debug("ftsdc010: cmd timeout (op code=%d)\n",
95*4882a593Smuzhiyun mmc_cmd->cmdidx);
96*4882a593Smuzhiyun } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
97*4882a593Smuzhiyun chip->acmd = 1;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return ret;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
ftsdc010_clkset(struct mmc * mmc,uint32_t rate)103*4882a593Smuzhiyun static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun struct ftsdc010_chip *chip = mmc->priv;
106*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs = chip->regs;
107*4882a593Smuzhiyun uint32_t div;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun for (div = 0; div < 0x7f; ++div) {
110*4882a593Smuzhiyun if (rate >= chip->sclk / (2 * (div + 1)))
111*4882a593Smuzhiyun break;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun chip->rate = chip->sclk / (2 * (div + 1));
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun writel(FTSDC010_CCR_CLK_DIV(div), ®s->ccr);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (IS_SD(mmc)) {
118*4882a593Smuzhiyun setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (chip->rate > 25000000)
121*4882a593Smuzhiyun setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD);
122*4882a593Smuzhiyun else
123*4882a593Smuzhiyun clrbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
ftsdc010_wait(struct ftsdc010_mmc __iomem * regs,uint32_t mask)127*4882a593Smuzhiyun static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun int ret = -ETIMEDOUT;
130*4882a593Smuzhiyun uint32_t st, ts;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
133*4882a593Smuzhiyun st = readl(®s->status);
134*4882a593Smuzhiyun if (!(st & mask))
135*4882a593Smuzhiyun continue;
136*4882a593Smuzhiyun writel(st & mask, ®s->clr);
137*4882a593Smuzhiyun ret = 0;
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (ret)
142*4882a593Smuzhiyun debug("ftsdc010: wait st(0x%x) timeout\n", mask);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun return ret;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /*
148*4882a593Smuzhiyun * u-boot mmc api
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun
ftsdc010_request(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)151*4882a593Smuzhiyun static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
152*4882a593Smuzhiyun struct mmc_data *data)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun int ret = -EOPNOTSUPP;
155*4882a593Smuzhiyun uint32_t len = 0;
156*4882a593Smuzhiyun struct ftsdc010_chip *chip = mmc->priv;
157*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs = chip->regs;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
160*4882a593Smuzhiyun printf("ftsdc010: the card is write protected!\n");
161*4882a593Smuzhiyun return ret;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (data) {
165*4882a593Smuzhiyun uint32_t dcr;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun len = data->blocksize * data->blocks;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /* 1. data disable + fifo reset */
170*4882a593Smuzhiyun dcr = 0;
171*4882a593Smuzhiyun #ifdef CONFIG_FTSDC010_SDIO
172*4882a593Smuzhiyun dcr |= FTSDC010_DCR_FIFO_RST;
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun writel(dcr, ®s->dcr);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* 2. clear status register */
177*4882a593Smuzhiyun writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
178*4882a593Smuzhiyun | FTSDC010_STATUS_FIFO_ORUN, ®s->clr);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* 3. data timeout (1 sec) */
181*4882a593Smuzhiyun writel(chip->rate, ®s->dtr);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* 4. data length (bytes) */
184*4882a593Smuzhiyun writel(len, ®s->dlr);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* 5. data enable */
187*4882a593Smuzhiyun dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
188*4882a593Smuzhiyun if (data->flags & MMC_DATA_WRITE)
189*4882a593Smuzhiyun dcr |= FTSDC010_DCR_DATA_WRITE;
190*4882a593Smuzhiyun writel(dcr, ®s->dcr);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun ret = ftsdc010_send_cmd(mmc, cmd);
194*4882a593Smuzhiyun if (ret) {
195*4882a593Smuzhiyun printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
196*4882a593Smuzhiyun return ret;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (!data)
200*4882a593Smuzhiyun return ret;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (data->flags & MMC_DATA_WRITE) {
203*4882a593Smuzhiyun const uint8_t *buf = (const uint8_t *)data->src;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun while (len > 0) {
206*4882a593Smuzhiyun int wlen;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* wait for tx ready */
209*4882a593Smuzhiyun ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
210*4882a593Smuzhiyun if (ret)
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* write bytes to ftsdc010 */
214*4882a593Smuzhiyun for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
215*4882a593Smuzhiyun writel(*(uint32_t *)buf, ®s->dwr);
216*4882a593Smuzhiyun buf += 4;
217*4882a593Smuzhiyun wlen += 4;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun len -= wlen;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun } else {
224*4882a593Smuzhiyun uint8_t *buf = (uint8_t *)data->dest;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun while (len > 0) {
227*4882a593Smuzhiyun int rlen;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* wait for rx ready */
230*4882a593Smuzhiyun ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
231*4882a593Smuzhiyun if (ret)
232*4882a593Smuzhiyun break;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /* fetch bytes from ftsdc010 */
235*4882a593Smuzhiyun for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
236*4882a593Smuzhiyun *(uint32_t *)buf = readl(®s->dwr);
237*4882a593Smuzhiyun buf += 4;
238*4882a593Smuzhiyun rlen += 4;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun len -= rlen;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun if (!ret) {
247*4882a593Smuzhiyun ret = ftsdc010_wait(regs,
248*4882a593Smuzhiyun FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return ret;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
ftsdc010_set_ios(struct mmc * mmc)254*4882a593Smuzhiyun static int ftsdc010_set_ios(struct mmc *mmc)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun struct ftsdc010_chip *chip = mmc->priv;
257*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs = chip->regs;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ftsdc010_clkset(mmc, mmc->clock);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun clrbits_le32(®s->bwr, FTSDC010_BWR_MODE_MASK);
262*4882a593Smuzhiyun switch (mmc->bus_width) {
263*4882a593Smuzhiyun case 4:
264*4882a593Smuzhiyun setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT);
265*4882a593Smuzhiyun break;
266*4882a593Smuzhiyun case 8:
267*4882a593Smuzhiyun setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT);
268*4882a593Smuzhiyun break;
269*4882a593Smuzhiyun default:
270*4882a593Smuzhiyun setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT);
271*4882a593Smuzhiyun break;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun return 0;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
ftsdc010_init(struct mmc * mmc)277*4882a593Smuzhiyun static int ftsdc010_init(struct mmc *mmc)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun struct ftsdc010_chip *chip = mmc->priv;
280*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs = chip->regs;
281*4882a593Smuzhiyun uint32_t ts;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun if (readl(®s->status) & FTSDC010_STATUS_CARD_DETECT)
284*4882a593Smuzhiyun return -ENOMEDIUM;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) {
287*4882a593Smuzhiyun printf("ftsdc010: write protected\n");
288*4882a593Smuzhiyun chip->wprot = 1;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun chip->fifo = (readl(®s->feature) & 0xff) << 2;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun /* 1. chip reset */
294*4882a593Smuzhiyun writel(FTSDC010_CMD_SDC_RST, ®s->cmd);
295*4882a593Smuzhiyun for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
296*4882a593Smuzhiyun if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST)
297*4882a593Smuzhiyun continue;
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) {
301*4882a593Smuzhiyun printf("ftsdc010: reset failed\n");
302*4882a593Smuzhiyun return -EOPNOTSUPP;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* 2. enter low speed mode (400k card detection) */
306*4882a593Smuzhiyun ftsdc010_clkset(mmc, 400000);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* 3. interrupt disabled */
309*4882a593Smuzhiyun writel(0, ®s->int_mask);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun static const struct mmc_ops ftsdc010_ops = {
315*4882a593Smuzhiyun .send_cmd = ftsdc010_request,
316*4882a593Smuzhiyun .set_ios = ftsdc010_set_ios,
317*4882a593Smuzhiyun .init = ftsdc010_init,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun
ftsdc010_mmc_init(int devid)320*4882a593Smuzhiyun int ftsdc010_mmc_init(int devid)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun struct mmc *mmc;
323*4882a593Smuzhiyun struct ftsdc010_chip *chip;
324*4882a593Smuzhiyun struct ftsdc010_mmc __iomem *regs;
325*4882a593Smuzhiyun #ifdef CONFIG_FTSDC010_BASE_LIST
326*4882a593Smuzhiyun uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun if (devid < 0 || devid >= ARRAY_SIZE(base_list))
329*4882a593Smuzhiyun return -1;
330*4882a593Smuzhiyun regs = (void __iomem *)base_list[devid];
331*4882a593Smuzhiyun #else
332*4882a593Smuzhiyun regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
333*4882a593Smuzhiyun #endif
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun chip = malloc(sizeof(struct ftsdc010_chip));
336*4882a593Smuzhiyun if (!chip)
337*4882a593Smuzhiyun return -ENOMEM;
338*4882a593Smuzhiyun memset(chip, 0, sizeof(struct ftsdc010_chip));
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun chip->regs = regs;
341*4882a593Smuzhiyun #ifdef CONFIG_SYS_CLK_FREQ
342*4882a593Smuzhiyun chip->sclk = CONFIG_SYS_CLK_FREQ;
343*4882a593Smuzhiyun #else
344*4882a593Smuzhiyun chip->sclk = clk_get_rate("SDC");
345*4882a593Smuzhiyun #endif
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun chip->cfg.name = "ftsdc010";
348*4882a593Smuzhiyun chip->cfg.ops = &ftsdc010_ops;
349*4882a593Smuzhiyun chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
350*4882a593Smuzhiyun switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) {
351*4882a593Smuzhiyun case FTSDC010_BWR_CAPS_4BIT:
352*4882a593Smuzhiyun chip->cfg.host_caps |= MMC_MODE_4BIT;
353*4882a593Smuzhiyun break;
354*4882a593Smuzhiyun case FTSDC010_BWR_CAPS_8BIT:
355*4882a593Smuzhiyun chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun default:
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun chip->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
362*4882a593Smuzhiyun chip->cfg.f_max = chip->sclk / 2;
363*4882a593Smuzhiyun chip->cfg.f_min = chip->sclk / 0x100;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun chip->cfg.part_type = PART_TYPE_DOS;
366*4882a593Smuzhiyun chip->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun mmc = mmc_create(&chip->cfg, chip);
369*4882a593Smuzhiyun if (mmc == NULL) {
370*4882a593Smuzhiyun free(chip);
371*4882a593Smuzhiyun return -ENOMEM;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun return 0;
375*4882a593Smuzhiyun }
376