blob: fbdbcf73ff4dc9d126a1ae9c47130000a4d69137 [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
Bin Meng6b82a242021-02-02 10:48:46 +080081 if (!resp || !resp_size)
82 return 0;
83
Bhargav Shaha1afe252019-07-08 04:10:48 +000084 debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
85 "resp_size=%d resp_match=%d resp_match_value=0x%x\n",
86 __func__, cmdidx, cmdarg, resp_type,
87 resp_size, resp_match, resp_match_value);
88
Thomas Chou1254c3d2010-12-24 13:12:21 +000089 cmdo[0] = 0xff;
90 cmdo[1] = MMC_SPI_CMD(cmdidx);
91 cmdo[2] = cmdarg >> 24;
92 cmdo[3] = cmdarg >> 16;
93 cmdo[4] = cmdarg >> 8;
94 cmdo[5] = cmdarg;
95 cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
Anup Pateld2c68c02019-07-17 04:23:38 +000096 ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, SPI_XFER_BEGIN);
Bhargav Shaha1afe252019-07-08 04:10:48 +000097 if (ret)
98 return ret;
99
100 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
101 if (ret)
102 return ret;
103
Bhargav Shaha1afe252019-07-08 04:10:48 +0000104 debug("%s: cmd%d", __func__, cmdidx);
105
Bin Mengd3a26712021-02-02 10:48:47 +0800106 if (resp_match)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000107 r = ~resp_match_value;
Bin Mengd3a26712021-02-02 10:48:47 +0800108 i = CMD_TIMEOUT;
109 while (i) {
110 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++;
115 i--;
Pragnesh Patel32ca52e2020-06-29 15:17:24 +0530116
Bin Mengd3a26712021-02-02 10:48:47 +0800117 if (resp_match) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000118 if (r == resp_match_value)
119 break;
Bin Mengd3a26712021-02-02 10:48:47 +0800120 } else {
121 if (!(r & 0x80))
122 break;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000123 }
Bin Mengd3a26712021-02-02 10:48:47 +0800124
125 if (!i)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000126 return -ETIMEDOUT;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000127 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000128
Bin Mengd3a26712021-02-02 10:48:47 +0800129 resp[0] = r;
130 for (i = 1; i < resp_size; i++) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000131 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
132 if (ret)
133 return ret;
134 debug(" resp%d=0x%x", rpos, r);
135 rpos++;
136 resp[i] = r;
137 }
138
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530139 if (r1b == true) {
140 i = R1B_TIMEOUT;
141 while (i) {
142 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
143 if (ret)
144 return ret;
145
146 debug(" resp%d=0x%x", rpos, r);
147 rpos++;
148 i--;
149
150 if (r)
151 break;
152 }
153 if (!i)
154 return -ETIMEDOUT;
155 }
156
Bhargav Shaha1afe252019-07-08 04:10:48 +0000157 debug("\n");
158
159 return 0;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000160}
161
Bhargav Shaha1afe252019-07-08 04:10:48 +0000162static int mmc_spi_readdata(struct udevice *dev,
163 void *xbuf, u32 bcnt, u32 bsize)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000164{
Thomas Chou1254c3d2010-12-24 13:12:21 +0000165 u16 crc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000166 u8 *buf = xbuf, r1;
167 int i, ret = 0;
168
Thomas Chou1254c3d2010-12-24 13:12:21 +0000169 while (bcnt--) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000170 for (i = 0; i < READ_TIMEOUT; i++) {
171 ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
172 if (ret)
173 return ret;
174 if (r1 == SPI_TOKEN_SINGLE)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000175 break;
176 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000177 debug("%s: data tok%d 0x%x\n", __func__, i, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000178 if (r1 == SPI_TOKEN_SINGLE) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000179 ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
180 if (ret)
181 return ret;
182 ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
183 if (ret)
184 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000185#ifdef CONFIG_MMC_SPI_CRC_ON
Bin Mengce387d92021-02-02 10:32:48 +0800186 u16 crc_ok = be16_to_cpu(crc16_ccitt(0, buf, bsize));
187 if (crc_ok != crc) {
188 debug("%s: data crc error, expected %04x got %04x\n",
189 __func__, crc_ok, crc);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000190 r1 = R1_SPI_COM_CRC;
191 break;
192 }
193#endif
194 r1 = 0;
195 } else {
196 r1 = R1_SPI_ERROR;
197 break;
198 }
199 buf += bsize;
200 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000201
202 if (r1 & R1_SPI_COM_CRC)
203 ret = -ECOMM;
204 else if (r1) /* other errors */
205 ret = -ETIMEDOUT;
206
207 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000208}
209
Bhargav Shaha1afe252019-07-08 04:10:48 +0000210static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
211 u32 bcnt, u32 bsize, int multi)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000212{
Thomas Chou1254c3d2010-12-24 13:12:21 +0000213 const u8 *buf = xbuf;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000214 u8 r1, tok[2];
Thomas Chou1254c3d2010-12-24 13:12:21 +0000215 u16 crc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000216 int i, ret = 0;
217
Thomas Chou1254c3d2010-12-24 13:12:21 +0000218 tok[0] = 0xff;
219 tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000220
Thomas Chou1254c3d2010-12-24 13:12:21 +0000221 while (bcnt--) {
222#ifdef CONFIG_MMC_SPI_CRC_ON
Stefan Roese084ff1e2016-03-03 09:34:12 +0100223 crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));
Thomas Chou1254c3d2010-12-24 13:12:21 +0000224#endif
Bhargav Shaha1afe252019-07-08 04:10:48 +0000225 dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
226 dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
227 dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
228 for (i = 0; i < CMD_TIMEOUT; i++) {
229 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000230 if ((r1 & 0x10) == 0) /* response token */
231 break;
232 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000233 debug("%s: data tok%d 0x%x\n", __func__, i, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000234 if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000235 debug("%s: data accepted\n", __func__);
236 for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
237 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000238 if (i && r1 == 0xff) {
239 r1 = 0;
240 break;
241 }
242 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000243 if (i == WRITE_TIMEOUT) {
244 debug("%s: data write timeout 0x%x\n",
245 __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000246 r1 = R1_SPI_ERROR;
247 break;
248 }
249 } else {
Bhargav Shaha1afe252019-07-08 04:10:48 +0000250 debug("%s: data error 0x%x\n", __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000251 r1 = R1_SPI_COM_CRC;
252 break;
253 }
254 buf += bsize;
255 }
256 if (multi && bcnt == -1) { /* stop multi write */
257 tok[1] = SPI_TOKEN_STOP_TRAN;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000258 dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
259 for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
260 dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000261 if (i && r1 == 0xff) {
262 r1 = 0;
263 break;
264 }
265 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000266 if (i == WRITE_TIMEOUT) {
267 debug("%s: data write timeout 0x%x\n", __func__, r1);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000268 r1 = R1_SPI_ERROR;
269 }
270 }
Thomas Chou1254c3d2010-12-24 13:12:21 +0000271
Bhargav Shaha1afe252019-07-08 04:10:48 +0000272 if (r1 & R1_SPI_COM_CRC)
Jaehoon Chung7825d202016-07-19 16:33:36 +0900273 ret = -ECOMM;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000274 else if (r1) /* other errors */
Jaehoon Chung7825d202016-07-19 16:33:36 +0900275 ret = -ETIMEDOUT;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000276
277 return ret;
278}
279
280static int dm_mmc_spi_set_ios(struct udevice *dev)
281{
282 return 0;
283}
284
285static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
286 struct mmc_data *data)
287{
288 int i, multi, ret = 0;
289 u8 *resp = NULL;
290 u32 resp_size = 0;
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530291 bool resp_match = false, r1b = false;
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530292 u8 resp8 = 0, resp16[2] = { 0 }, resp40[5] = { 0 }, resp_match_value = 0;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000293
294 dm_spi_claim_bus(dev);
295
296 for (i = 0; i < 4; i++)
297 cmd->response[i] = 0;
298
299 switch (cmd->cmdidx) {
300 case SD_CMD_APP_SEND_OP_COND:
301 case MMC_CMD_SEND_OP_COND:
302 resp = &resp8;
303 resp_size = sizeof(resp8);
304 cmd->cmdarg = 0x40000000;
305 break;
306 case SD_CMD_SEND_IF_COND:
307 resp = (u8 *)&resp40[0];
308 resp_size = sizeof(resp40);
309 resp_match = true;
310 resp_match_value = R1_SPI_IDLE;
311 break;
312 case MMC_CMD_SPI_READ_OCR:
313 resp = (u8 *)&resp40[0];
314 resp_size = sizeof(resp40);
315 break;
316 case MMC_CMD_SEND_STATUS:
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530317 resp = (u8 *)&resp16[0];
318 resp_size = sizeof(resp16);
319 break;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000320 case MMC_CMD_SET_BLOCKLEN:
321 case MMC_CMD_SPI_CRC_ON_OFF:
Bhargav Shaha1afe252019-07-08 04:10:48 +0000322 resp = &resp8;
323 resp_size = sizeof(resp8);
324 resp_match = true;
325 resp_match_value = 0x0;
326 break;
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530327 case MMC_CMD_STOP_TRANSMISSION:
328 case MMC_CMD_ERASE:
329 resp = &resp8;
330 resp_size = sizeof(resp8);
331 r1b = true;
332 break;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000333 case MMC_CMD_SEND_CSD:
334 case MMC_CMD_SEND_CID:
335 case MMC_CMD_READ_SINGLE_BLOCK:
336 case MMC_CMD_READ_MULTIPLE_BLOCK:
337 case MMC_CMD_WRITE_SINGLE_BLOCK:
338 case MMC_CMD_WRITE_MULTIPLE_BLOCK:
Pragnesh Patela01f57e2020-06-29 15:17:26 +0530339 case MMC_CMD_APP_CMD:
Pragnesh Patel536b4562020-06-29 15:17:28 +0530340 case SD_CMD_ERASE_WR_BLK_START:
341 case SD_CMD_ERASE_WR_BLK_END:
Pragnesh Patel049dc5f2020-06-29 15:17:25 +0530342 resp = &resp8;
343 resp_size = sizeof(resp8);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000344 break;
345 default:
346 resp = &resp8;
347 resp_size = sizeof(resp8);
348 resp_match = true;
349 resp_match_value = R1_SPI_IDLE;
350 break;
351 };
352
353 ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type,
Pragnesh Patel0f26cf12020-06-29 15:17:29 +0530354 resp, resp_size, resp_match, resp_match_value, r1b);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000355 if (ret)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000356 goto done;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000357
358 switch (cmd->cmdidx) {
359 case SD_CMD_APP_SEND_OP_COND:
360 case MMC_CMD_SEND_OP_COND:
361 cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
362 break;
363 case SD_CMD_SEND_IF_COND:
364 case MMC_CMD_SPI_READ_OCR:
365 cmd->response[0] = resp40[4];
366 cmd->response[0] |= (uint)resp40[3] << 8;
367 cmd->response[0] |= (uint)resp40[2] << 16;
368 cmd->response[0] |= (uint)resp40[1] << 24;
369 break;
370 case MMC_CMD_SEND_STATUS:
Pragnesh Patel68fbc9d2020-06-29 15:17:27 +0530371 if (resp16[0] || resp16[1])
372 cmd->response[0] = MMC_STATUS_ERROR;
373 else
374 cmd->response[0] = MMC_STATUS_RDY_FOR_DATA;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000375 break;
376 case MMC_CMD_SEND_CID:
377 case MMC_CMD_SEND_CSD:
378 ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
379 if (ret)
380 return ret;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000381 for (i = 0; i < 4; i++)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000382 cmd->response[i] =
383 cpu_to_be32(cmd->response[i]);
384 break;
385 default:
386 cmd->response[0] = resp8;
387 break;
388 }
389
390 debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n",
391 __func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
392 cmd->response[2], cmd->response[3]);
393
394 if (data) {
395 debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
396 __func__, data->flags, data->blocks, data->blocksize);
397 multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000398 if (data->flags == MMC_DATA_READ)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000399 ret = mmc_spi_readdata(dev, data->dest,
400 data->blocks, data->blocksize);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000401 else if (data->flags == MMC_DATA_WRITE)
Bhargav Shaha1afe252019-07-08 04:10:48 +0000402 ret = mmc_spi_writedata(dev, data->src,
403 data->blocks, data->blocksize,
404 multi);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000405 }
Bhargav Shaha1afe252019-07-08 04:10:48 +0000406
Thomas Chou1254c3d2010-12-24 13:12:21 +0000407done:
Anup Pateld2c68c02019-07-17 04:23:38 +0000408 dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
409
Bhargav Shaha1afe252019-07-08 04:10:48 +0000410 dm_spi_release_bus(dev);
411
Thomas Chou1254c3d2010-12-24 13:12:21 +0000412 return ret;
413}
414
Bhargav Shaha1afe252019-07-08 04:10:48 +0000415static int mmc_spi_probe(struct udevice *dev)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000416{
Bhargav Shaha1afe252019-07-08 04:10:48 +0000417 struct mmc_spi_priv *priv = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700418 struct mmc_spi_plat *plat = dev_get_plat(dev);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000419 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
420 char *name;
421
422 priv->spi = dev_get_parent_priv(dev);
423 if (!priv->spi->max_hz)
424 priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000425 priv->spi->mode = SPI_MODE_0;
426 priv->spi->wordlen = 8;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200427
Bhargav Shaha1afe252019-07-08 04:10:48 +0000428 name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
429 if (!name)
430 return -ENOMEM;
431 sprintf(name, "%s:%s", dev->parent->name, dev->name);
432
Bin Mengf7260322019-08-30 21:15:33 -0700433 plat->cfg.name = name;
434 plat->cfg.host_caps = MMC_MODE_SPI;
435 plat->cfg.voltages = MMC_SPI_VOLTAGE;
436 plat->cfg.f_min = MMC_SPI_MIN_CLOCK;
437 plat->cfg.f_max = priv->spi->max_hz;
438 plat->cfg.part_type = PART_TYPE_DOS;
439 plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000440
Bin Mengf7260322019-08-30 21:15:33 -0700441 plat->mmc.cfg = &plat->cfg;
442 plat->mmc.priv = priv;
443 plat->mmc.dev = dev;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000444
Bin Mengf7260322019-08-30 21:15:33 -0700445 upriv->mmc = &plat->mmc;
Bhargav Shaha1afe252019-07-08 04:10:48 +0000446
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900447 return 0;
Thomas Chou1254c3d2010-12-24 13:12:21 +0000448}
449
Bhargav Shaha1afe252019-07-08 04:10:48 +0000450static int mmc_spi_bind(struct udevice *dev)
Thomas Chou1254c3d2010-12-24 13:12:21 +0000451{
Simon Glassfa20e932020-12-03 16:55:20 -0700452 struct mmc_spi_plat *plat = dev_get_plat(dev);
Bhargav Shaha1afe252019-07-08 04:10:48 +0000453
Bin Mengf7260322019-08-30 21:15:33 -0700454 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Thomas Chou1254c3d2010-12-24 13:12:21 +0000455}
456
Bhargav Shaha1afe252019-07-08 04:10:48 +0000457static const struct dm_mmc_ops mmc_spi_ops = {
458 .send_cmd = dm_mmc_spi_request,
459 .set_ios = dm_mmc_spi_set_ios,
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200460};
461
Bhargav Shaha1afe252019-07-08 04:10:48 +0000462static const struct udevice_id dm_mmc_spi_match[] = {
463 { .compatible = "mmc-spi-slot" },
464 { /* sentinel */ }
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200465};
466
Bhargav Shaha1afe252019-07-08 04:10:48 +0000467U_BOOT_DRIVER(mmc_spi) = {
468 .name = "mmc_spi",
469 .id = UCLASS_MMC,
470 .of_match = dm_mmc_spi_match,
471 .ops = &mmc_spi_ops,
472 .probe = mmc_spi_probe,
473 .bind = mmc_spi_bind,
Simon Glass71fa5b42020-12-03 16:55:18 -0700474 .plat_auto = sizeof(struct mmc_spi_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700475 .priv_auto = sizeof(struct mmc_spi_priv),
Bhargav Shaha1afe252019-07-08 04:10:48 +0000476};