blob: 51b1aa4372eb7ead85d3de7308b93e9de2654084 [file] [log] [blame]
Thomas Chou1254c3d2010-12-24 13:12:21 +00001/*
2 * generic mmc spi driver
3 *
4 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
Bhargav Shaha1afe252019-07-08 04:10:48 +00005 * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
6 *
Thomas Chou1254c3d2010-12-24 13:12:21 +00007 * Licensed under the GPL-2 or later.
8 */
9#include <common.h>
Jaehoon Chung7825d202016-07-19 16:33:36 +090010#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Thomas Chou1254c3d2010-12-24 13:12:21 +000012#include <malloc.h>
13#include <part.h>
14#include <mmc.h>
Bhargav Shaha1afe252019-07-08 04:10:48 +000015#include <stdlib.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Philipp Tomsich36b26d12018-11-25 19:22:18 +010017#include <u-boot/crc.h>
Thomas Chou1254c3d2010-12-24 13:12:21 +000018#include <linux/crc7.h>
Yoshinori Sato923c2072015-06-01 15:22:37 +090019#include <asm/byteorder.h>
Bhargav Shaha1afe252019-07-08 04:10:48 +000020#include <dm.h>
21#include <spi.h>
Thomas Chou1254c3d2010-12-24 13:12:21 +000022
23/* MMC/SD in SPI mode reports R1 status always */
Bhargav Shaha1afe252019-07-08 04:10:48 +000024#define R1_SPI_IDLE BIT(0)
25#define R1_SPI_ERASE_RESET BIT(1)
26#define R1_SPI_ILLEGAL_COMMAND BIT(2)
27#define R1_SPI_COM_CRC BIT(3)
28#define R1_SPI_ERASE_SEQ BIT(4)
29#define R1_SPI_ADDRESS BIT(5)
30#define R1_SPI_PARAMETER BIT(6)
Thomas Chou1254c3d2010-12-24 13:12:21 +000031/* R1 bit 7 is always zero, reuse this bit for error */
Bhargav Shaha1afe252019-07-08 04:10:48 +000032#define R1_SPI_ERROR BIT(7)
Thomas Chou1254c3d2010-12-24 13:12:21 +000033
34/* Response tokens used to ack each block written: */
35#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
36#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
37#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
38#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
39
40/* Read and write blocks start with these tokens and end with crc;
41 * on error, read tokens act like a subset of R2_SPI_* values.
42 */
Bhargav Shaha1afe252019-07-08 04:10:48 +000043/* single block write multiblock read */
44#define SPI_TOKEN_SINGLE 0xfe
45/* multiblock write */
46#define SPI_TOKEN_MULTI_WRITE 0xfc
47/* terminate multiblock write */
48#define SPI_TOKEN_STOP_TRAN 0xfd
Thomas Chou1254c3d2010-12-24 13:12:21 +000049
50/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
Bhargav Shaha1afe252019-07-08 04:10:48 +000051#define MMC_SPI_CMD(x) (0x40 | (x))
Thomas Chou1254c3d2010-12-24 13:12:21 +000052
53/* bus capability */
Bhargav Shaha1afe252019-07-08 04:10:48 +000054#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
55#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
56#define MMC_SPI_MAX_CLOCK 25000000 /* SD/MMC legacy speed */
Thomas Chou1254c3d2010-12-24 13:12:21 +000057
58/* timeout value */
Bhargav Shaha1afe252019-07-08 04:10:48 +000059#define CMD_TIMEOUT 8
60#define READ_TIMEOUT 3000000 /* 1 sec */
61#define WRITE_TIMEOUT 3000000 /* 1 sec */
Pragnesh Patel0f26cf12020-06-29 15:17:29 +053062#define R1B_TIMEOUT 3000000 /* 1 sec */
Bhargav Shaha1afe252019-07-08 04:10:48 +000063
Bin Mengf7260322019-08-30 21:15:33 -070064struct mmc_spi_plat {
Bhargav Shaha1afe252019-07-08 04:10:48 +000065 struct mmc_config cfg;
66 struct mmc mmc;
67};
Thomas Chou1254c3d2010-12-24 13:12:21 +000068
Bin Mengf7260322019-08-30 21:15:33 -070069struct mmc_spi_priv {
70 struct spi_slave *spi;
71};
72
Bhargav Shaha1afe252019-07-08 04:10:48 +000073static int mmc_spi_sendcmd(struct udevice *dev,
74 ushort cmdidx, u32 cmdarg, u32 resp_type,
75 u8 *resp, u32 resp_size,
Pragnesh Patel0f26cf12020-06-29 15:17:29 +053076 bool resp_match, u8 resp_match_value, bool r1b)
Thomas Chou1254c3d2010-12-24 13:12:21 +000077{
Bhargav Shaha1afe252019-07-08 04:10:48 +000078 int i, rpos = 0, ret = 0;
79 u8 cmdo[7], r;
80
81 debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
82 "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
83 __func__, cmdidx, cmdarg, resp_type,
84 resp_size, resp_match, resp_match_value);
85
Thomas Chou1254c3d2010-12-24 13:12:21 +000086 cmdo[0] = 0xff;
87 cmdo[1] = MMC_SPI_CMD(cmdidx);
88 cmdo[2] = cmdarg >> 24;
89 cmdo[3] = cmdarg >> 16;
90 cmdo[4] = cmdarg >> 8;
91 cmdo[5] = cmdarg;
92 cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
Anup Pateld2c68c02019-07-17 04:23:38 +000093 ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, SPI_XFER_BEGIN);
Bhargav Shaha1afe252019-07-08 04:10:48 +000094 if (ret)
95 return ret;
96
97 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
98 if (ret)
99 return ret;
100
101 if (!resp || !resp_size)
102 return 0;
103
104 debug("%s: cmd%d", __func__, cmdidx);
105
106 if (resp_match) {
107 r = ~resp_match_value;
108 i = CMD_TIMEOUT;
Pragnesh Patel32ca52e2020-06-29 15:17:24 +0530109 while (i) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000110 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
111 if (ret)
112 return ret;
113 debug(" resp%d=0x%x", rpos, r);
114 rpos++;
Pragnesh Patel32ca52e2020-06-29 15:17:24 +0530115 i--;
116
Bhargav Shaha1afe252019-07-08 04:10:48 +0000117 if (r == resp_match_value)
118 break;
119 }
120 if (!i && (r != resp_match_value))
121 return -ETIMEDOUT;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000122 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000123
124 for (i = 0; i < resp_size; i++) {
125 if (i == 0 && resp_match) {
126 resp[i] = resp_match_value;
127 continue;
128 }
129 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
130 if (ret)
131 return ret;
132 debug(" resp%d=0x%x", rpos, r);
133 rpos++;
134 resp[i] = r;
135 }
136
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530137 if (r1b == true) {
138 i = R1B_TIMEOUT;
139 while (i) {
140 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
141 if (ret)
142 return ret;
143
144 debug(" resp%d=0x%x", rpos, r);
145 rpos++;
146 i--;
147
148 if (r)
149 break;
150 }
151 if (!i)
152 return -ETIMEDOUT;
153 }
154
Bhargav Shaha1afe252019-07-08 04:10:48 +0000155 debug("\n");
156
157 return 0;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000158}
159
Bhargav Shaha1afe252019-07-08 04:10:48 +0000160static int mmc_spi_readdata(struct udevice *dev,
161 void *xbuf, u32 bcnt, u32 bsize)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000162{
Thomas Chou1254c3d2010-12-24 13:12:21 +0000163 u16 crc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000164 u8 *buf = xbuf, r1;
165 int i, ret = 0;
166
Thomas Chou1254c3d2010-12-24 13:12:21 +0000167 while (bcnt--) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000168 for (i = 0; i < READ_TIMEOUT; i++) {
169 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
170 if (ret)
171 return ret;
172 if (r1 == SPI_TOKEN_SINGLE)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000173 break;
174 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000175 debug("%s: data tok%d 0x%x\n", __func__, i, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000176 if (r1 == SPI_TOKEN_SINGLE) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000177 ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
178 if (ret)
179 return ret;
180 ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
181 if (ret)
182 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000183#ifdef CONFIG_MMC_SPI_CRC_ON
Bhargav Shaha1afe252019-07-08 04:10:48 +0000184 if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
185 debug("%s: data crc error\n", __func__);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000186 r1 = R1_SPI_COM_CRC;
187 break;
188 }
189#endif
190 r1 = 0;
191 } else {
192 r1 = R1_SPI_ERROR;
193 break;
194 }
195 buf += bsize;
196 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000197
198 if (r1 & R1_SPI_COM_CRC)
199 ret = -ECOMM;
200 else if (r1) /* other errors */
201 ret = -ETIMEDOUT;
202
203 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000204}
205
Bhargav Shaha1afe252019-07-08 04:10:48 +0000206static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
207 u32 bcnt, u32 bsize, int multi)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000208{
Thomas Chou1254c3d2010-12-24 13:12:21 +0000209 const u8 *buf = xbuf;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000210 u8 r1, tok[2];
Thomas Chou1254c3d2010-12-24 13:12:21 +0000211 u16 crc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000212 int i, ret = 0;
213
Thomas Chou1254c3d2010-12-24 13:12:21 +0000214 tok[0] = 0xff;
215 tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000216
Thomas Chou1254c3d2010-12-24 13:12:21 +0000217 while (bcnt--) {
218#ifdef CONFIG_MMC_SPI_CRC_ON
Stefan Roese084ff1e2016-03-03 09:34:12 +0100219 crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));
Thomas Chou1254c3d2010-12-24 13:12:21 +0000220#endif
Bhargav Shaha1afe252019-07-08 04:10:48 +0000221 dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
222 dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
223 dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
224 for (i = 0; i < CMD_TIMEOUT; i++) {
225 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000226 if ((r1 & 0x10) == 0) /* response token */
227 break;
228 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000229 debug("%s: data tok%d 0x%x\n", __func__, i, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000230 if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000231 debug("%s: data accepted\n", __func__);
232 for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
233 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000234 if (i && r1 == 0xff) {
235 r1 = 0;
236 break;
237 }
238 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000239 if (i == WRITE_TIMEOUT) {
240 debug("%s: data write timeout 0x%x\n",
241 __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000242 r1 = R1_SPI_ERROR;
243 break;
244 }
245 } else {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000246 debug("%s: data error 0x%x\n", __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000247 r1 = R1_SPI_COM_CRC;
248 break;
249 }
250 buf += bsize;
251 }
252 if (multi && bcnt == -1) { /* stop multi write */
253 tok[1] = SPI_TOKEN_STOP_TRAN;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000254 dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
255 for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
256 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000257 if (i && r1 == 0xff) {
258 r1 = 0;
259 break;
260 }
261 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000262 if (i == WRITE_TIMEOUT) {
263 debug("%s: data write timeout 0x%x\n", __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000264 r1 = R1_SPI_ERROR;
265 }
266 }
Thomas Chou1254c3d2010-12-24 13:12:21 +0000267
Bhargav Shaha1afe252019-07-08 04:10:48 +0000268 if (r1 & R1_SPI_COM_CRC)
Jaehoon Chung7825d202016-07-19 16:33:36 +0900269 ret = -ECOMM;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000270 else if (r1) /* other errors */
Jaehoon Chung7825d202016-07-19 16:33:36 +0900271 ret = -ETIMEDOUT;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000272
273 return ret;
274}
275
276static int dm_mmc_spi_set_ios(struct udevice *dev)
277{
278 return 0;
279}
280
281static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
282 struct mmc_data *data)
283{
284 int i, multi, ret = 0;
285 u8 *resp = NULL;
286 u32 resp_size = 0;
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530287 bool resp_match = false, r1b = false;
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530288 u8 resp8 = 0, resp16[2] = { 0 }, resp40[5] = { 0 }, resp_match_value = 0;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000289
290 dm_spi_claim_bus(dev);
291
292 for (i = 0; i < 4; i++)
293 cmd->response[i] = 0;
294
295 switch (cmd->cmdidx) {
296 case SD_CMD_APP_SEND_OP_COND:
297 case MMC_CMD_SEND_OP_COND:
298 resp = &resp8;
299 resp_size = sizeof(resp8);
300 cmd->cmdarg = 0x40000000;
301 break;
302 case SD_CMD_SEND_IF_COND:
303 resp = (u8 *)&resp40[0];
304 resp_size = sizeof(resp40);
305 resp_match = true;
306 resp_match_value = R1_SPI_IDLE;
307 break;
308 case MMC_CMD_SPI_READ_OCR:
309 resp = (u8 *)&resp40[0];
310 resp_size = sizeof(resp40);
311 break;
312 case MMC_CMD_SEND_STATUS:
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530313 resp = (u8 *)&resp16[0];
314 resp_size = sizeof(resp16);
315 break;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000316 case MMC_CMD_SET_BLOCKLEN:
317 case MMC_CMD_SPI_CRC_ON_OFF:
Bhargav Shaha1afe252019-07-08 04:10:48 +0000318 resp = &resp8;
319 resp_size = sizeof(resp8);
320 resp_match = true;
321 resp_match_value = 0x0;
322 break;
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530323 case MMC_CMD_STOP_TRANSMISSION:
324 case MMC_CMD_ERASE:
325 resp = &resp8;
326 resp_size = sizeof(resp8);
327 r1b = true;
328 break;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000329 case MMC_CMD_SEND_CSD:
330 case MMC_CMD_SEND_CID:
331 case MMC_CMD_READ_SINGLE_BLOCK:
332 case MMC_CMD_READ_MULTIPLE_BLOCK:
333 case MMC_CMD_WRITE_SINGLE_BLOCK:
334 case MMC_CMD_WRITE_MULTIPLE_BLOCK:
Pragnesh Patela01f57e2020-06-29 15:17:26 +0530335 case MMC_CMD_APP_CMD:
Pragnesh Patel536b4562020-06-29 15:17:28 +0530336 case SD_CMD_ERASE_WR_BLK_START:
337 case SD_CMD_ERASE_WR_BLK_END:
Pragnesh Patel049dc5f2020-06-29 15:17:25 +0530338 resp = &resp8;
339 resp_size = sizeof(resp8);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000340 break;
341 default:
342 resp = &resp8;
343 resp_size = sizeof(resp8);
344 resp_match = true;
345 resp_match_value = R1_SPI_IDLE;
346 break;
347 };
348
349 ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type,
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530350 resp, resp_size, resp_match, resp_match_value, r1b);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000351 if (ret)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000352 goto done;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000353
354 switch (cmd->cmdidx) {
355 case SD_CMD_APP_SEND_OP_COND:
356 case MMC_CMD_SEND_OP_COND:
357 cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
358 break;
359 case SD_CMD_SEND_IF_COND:
360 case MMC_CMD_SPI_READ_OCR:
361 cmd->response[0] = resp40[4];
362 cmd->response[0] |= (uint)resp40[3] << 8;
363 cmd->response[0] |= (uint)resp40[2] << 16;
364 cmd->response[0] |= (uint)resp40[1] << 24;
365 break;
366 case MMC_CMD_SEND_STATUS:
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530367 if (resp16[0] || resp16[1])
368 cmd->response[0] = MMC_STATUS_ERROR;
369 else
370 cmd->response[0] = MMC_STATUS_RDY_FOR_DATA;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000371 break;
372 case MMC_CMD_SEND_CID:
373 case MMC_CMD_SEND_CSD:
374 ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
375 if (ret)
376 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000377 for (i = 0; i < 4; i++)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000378 cmd->response[i] =
379 cpu_to_be32(cmd->response[i]);
380 break;
381 default:
382 cmd->response[0] = resp8;
383 break;
384 }
385
386 debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n",
387 __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
388 cmd->response[2], cmd->response[3]);
389
390 if (data) {
391 debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
392 __func__, data->flags, data->blocks, data->blocksize);
393 multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000394 if (data->flags == MMC_DATA_READ)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000395 ret = mmc_spi_readdata(dev, data->dest,
396 data->blocks, data->blocksize);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000397 else if (data->flags == MMC_DATA_WRITE)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000398 ret = mmc_spi_writedata(dev, data->src,
399 data->blocks, data->blocksize,
400 multi);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000401 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000402
Thomas Chou1254c3d2010-12-24 13:12:21 +0000403done:
Anup Pateld2c68c02019-07-17 04:23:38 +0000404 dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
405
Bhargav Shaha1afe252019-07-08 04:10:48 +0000406 dm_spi_release_bus(dev);
407
Thomas Chou1254c3d2010-12-24 13:12:21 +0000408 return ret;
409}
410
Bhargav Shaha1afe252019-07-08 04:10:48 +0000411static int mmc_spi_probe(struct udevice *dev)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000412{
Bhargav Shaha1afe252019-07-08 04:10:48 +0000413 struct mmc_spi_priv *priv = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700414 struct mmc_spi_plat *plat = dev_get_plat(dev);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000415 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
416 char *name;
417
418 priv->spi = dev_get_parent_priv(dev);
419 if (!priv->spi->max_hz)
420 priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
421 priv->spi->speed = 0;
422 priv->spi->mode = SPI_MODE_0;
423 priv->spi->wordlen = 8;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200424
Bhargav Shaha1afe252019-07-08 04:10:48 +0000425 name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
426 if (!name)
427 return -ENOMEM;
428 sprintf(name, "%s:%s", dev->parent->name, dev->name);
429
Bin Mengf7260322019-08-30 21:15:33 -0700430 plat->cfg.name = name;
431 plat->cfg.host_caps = MMC_MODE_SPI;
432 plat->cfg.voltages = MMC_SPI_VOLTAGE;
433 plat->cfg.f_min = MMC_SPI_MIN_CLOCK;
434 plat->cfg.f_max = priv->spi->max_hz;
435 plat->cfg.part_type = PART_TYPE_DOS;
436 plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000437
Bin Mengf7260322019-08-30 21:15:33 -0700438 plat->mmc.cfg = &plat->cfg;
439 plat->mmc.priv = priv;
440 plat->mmc.dev = dev;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000441
Bin Mengf7260322019-08-30 21:15:33 -0700442 upriv->mmc = &plat->mmc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000443
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900444 return 0;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000445}
446
Bhargav Shaha1afe252019-07-08 04:10:48 +0000447static int mmc_spi_bind(struct udevice *dev)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000448{
Simon Glassfa20e932020-12-03 16:55:20 -0700449 struct mmc_spi_plat *plat = dev_get_plat(dev);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000450
Bin Mengf7260322019-08-30 21:15:33 -0700451 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000452}
453
Bhargav Shaha1afe252019-07-08 04:10:48 +0000454static const struct dm_mmc_ops mmc_spi_ops = {
455 .send_cmd = dm_mmc_spi_request,
456 .set_ios = dm_mmc_spi_set_ios,
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200457};
458
Bhargav Shaha1afe252019-07-08 04:10:48 +0000459static const struct udevice_id dm_mmc_spi_match[] = {
460 { .compatible = "mmc-spi-slot" },
461 { /* sentinel */ }
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200462};
463
Bhargav Shaha1afe252019-07-08 04:10:48 +0000464U_BOOT_DRIVER(mmc_spi) = {
465 .name = "mmc_spi",
466 .id = UCLASS_MMC,
467 .of_match = dm_mmc_spi_match,
468 .ops = &mmc_spi_ops,
469 .probe = mmc_spi_probe,
470 .bind = mmc_spi_bind,
Simon Glass71fa5b42020-12-03 16:55:18 -0700471 .plat_auto = sizeof(struct mmc_spi_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700472 .priv_auto = sizeof(struct mmc_spi_priv),
Bhargav Shaha1afe252019-07-08 04:10:48 +0000473};