Blame view
drivers/mmc/core/sd_ops.c
7.73 KB
da7fbe58d mmc: Separate out... |
1 |
/* |
70f10482c mmc: update heade... |
2 |
* linux/drivers/mmc/core/sd_ops.h |
da7fbe58d mmc: Separate out... |
3 4 5 6 7 8 9 10 |
* * Copyright 2006-2007 Pierre Ossman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. */ |
4f665cb61 mmc: fix mmc_app_... |
11 |
#include <linux/slab.h> |
da7fbe58d mmc: Separate out... |
12 |
#include <linux/types.h> |
3ef77af15 mmc: Add export.h... |
13 |
#include <linux/export.h> |
da7fbe58d mmc: Separate out... |
14 15 16 17 18 19 20 21 22 |
#include <linux/scatterlist.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> #include "core.h" #include "sd_ops.h" |
cb87ea28e mmc: core: Add mm... |
23 |
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) |
393618510 drivers/mmc/core/... |
24 25 |
{ int err; |
1278dba16 mmc: initialize s... |
26 |
struct mmc_command cmd = {0}; |
393618510 drivers/mmc/core/... |
27 28 29 30 31 32 33 34 |
BUG_ON(!host); BUG_ON(card && (card->host != host)); cmd.opcode = MMC_APP_CMD; if (card) { cmd.arg = card->rca << 16; |
af5171507 MMC core learns a... |
35 |
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; |
393618510 drivers/mmc/core/... |
36 37 |
} else { cmd.arg = 0; |
af5171507 MMC core learns a... |
38 |
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; |
393618510 drivers/mmc/core/... |
39 40 41 |
} err = mmc_wait_for_cmd(host, &cmd, 0); |
17b0429dd mmc: remove custo... |
42 |
if (err) |
393618510 drivers/mmc/core/... |
43 44 45 |
return err; /* Check that card supported application commands */ |
af5171507 MMC core learns a... |
46 |
if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) |
17b0429dd mmc: remove custo... |
47 |
return -EOPNOTSUPP; |
393618510 drivers/mmc/core/... |
48 |
|
17b0429dd mmc: remove custo... |
49 |
return 0; |
393618510 drivers/mmc/core/... |
50 |
} |
cb87ea28e mmc: core: Add mm... |
51 |
EXPORT_SYMBOL_GPL(mmc_app_cmd); |
393618510 drivers/mmc/core/... |
52 |
|
da7fbe58d mmc: Separate out... |
53 54 55 56 |
/** * mmc_wait_for_app_cmd - start an application command and wait for completion * @host: MMC host to start command |
67a61c484 mmc: update kerne... |
57 |
* @card: Card to send MMC_APP_CMD to |
da7fbe58d mmc: Separate out... |
58 59 60 61 62 63 64 65 66 67 68 |
* @cmd: MMC command to start * @retries: maximum number of retries * * Sends a MMC_APP_CMD, checks the card response, sends the command * in the parameter and waits for it to complete. Return any error * that occurred while the command was executing. Do not attempt to * parse the response. */ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) { |
ad5fd9728 mmc: fix integer ... |
69 |
struct mmc_request mrq = {NULL}; |
da7fbe58d mmc: Separate out... |
70 71 72 73 74 |
int i, err; BUG_ON(!cmd); BUG_ON(retries < 0); |
17b0429dd mmc: remove custo... |
75 |
err = -EIO; |
da7fbe58d mmc: Separate out... |
76 77 78 79 80 81 |
/* * We have to resend MMC_APP_CMD for each attempt so * we cannot use the retries field in mmc_command. */ for (i = 0;i <= retries;i++) { |
da7fbe58d mmc: Separate out... |
82 |
err = mmc_app_cmd(host, card); |
af5171507 MMC core learns a... |
83 84 85 86 87 88 |
if (err) { /* no point in retrying; no APP commands allowed */ if (mmc_host_is_spi(host)) { if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) break; } |
da7fbe58d mmc: Separate out... |
89 |
continue; |
af5171507 MMC core learns a... |
90 |
} |
da7fbe58d mmc: Separate out... |
91 92 93 94 95 96 97 98 99 100 101 102 |
memset(&mrq, 0, sizeof(struct mmc_request)); memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = 0; mrq.cmd = cmd; cmd->data = NULL; mmc_wait_for_req(host, &mrq); err = cmd->error; |
17b0429dd mmc: remove custo... |
103 |
if (!cmd->error) |
da7fbe58d mmc: Separate out... |
104 |
break; |
af5171507 MMC core learns a... |
105 106 107 108 109 110 |
/* no point in retrying illegal APP commands */ if (mmc_host_is_spi(host)) { if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) break; } |
da7fbe58d mmc: Separate out... |
111 112 113 114 115 116 |
} return err; } EXPORT_SYMBOL(mmc_wait_for_app_cmd); |
da7fbe58d mmc: Separate out... |
117 118 |
int mmc_app_set_bus_width(struct mmc_card *card, int width) { |
1278dba16 mmc: initialize s... |
119 |
struct mmc_command cmd = {0}; |
da7fbe58d mmc: Separate out... |
120 121 122 |
BUG_ON(!card); BUG_ON(!card->host); |
da7fbe58d mmc: Separate out... |
123 124 125 126 127 128 129 130 131 132 133 |
cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; switch (width) { case MMC_BUS_WIDTH_1: cmd.arg = SD_BUS_WIDTH_1; break; case MMC_BUS_WIDTH_4: cmd.arg = SD_BUS_WIDTH_4; break; default: |
17b0429dd mmc: remove custo... |
134 |
return -EINVAL; |
da7fbe58d mmc: Separate out... |
135 |
} |
0899e7419 mmc: remove unnec... |
136 |
return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); |
da7fbe58d mmc: Separate out... |
137 138 139 140 |
} int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { |
1278dba16 mmc: initialize s... |
141 |
struct mmc_command cmd = {0}; |
da7fbe58d mmc: Separate out... |
142 143 144 |
int i, err = 0; BUG_ON(!host); |
da7fbe58d mmc: Separate out... |
145 |
cmd.opcode = SD_APP_OP_COND; |
af5171507 MMC core learns a... |
146 147 148 149 150 |
if (mmc_host_is_spi(host)) cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ else cmd.arg = ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; |
da7fbe58d mmc: Separate out... |
151 152 153 |
for (i = 100; i; i--) { err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); |
17b0429dd mmc: remove custo... |
154 |
if (err) |
da7fbe58d mmc: Separate out... |
155 |
break; |
af5171507 MMC core learns a... |
156 157 |
/* if we're just probing, do a single pass */ if (ocr == 0) |
da7fbe58d mmc: Separate out... |
158 |
break; |
af5171507 MMC core learns a... |
159 160 161 162 163 164 165 166 |
/* otherwise wait until reset completes */ if (mmc_host_is_spi(host)) { if (!(cmd.resp[0] & R1_SPI_IDLE)) break; } else { if (cmd.resp[0] & MMC_CARD_BUSY) break; } |
17b0429dd mmc: remove custo... |
167 |
err = -ETIMEDOUT; |
da7fbe58d mmc: Separate out... |
168 169 170 |
mmc_delay(10); } |
5e863662a mmc: sd: warn if ... |
171 172 173 |
if (!i) pr_err("%s: card never left busy state ", mmc_hostname(host)); |
af5171507 MMC core learns a... |
174 |
if (rocr && !mmc_host_is_spi(host)) |
da7fbe58d mmc: Separate out... |
175 176 177 178 179 180 181 |
*rocr = cmd.resp[0]; return err; } int mmc_send_if_cond(struct mmc_host *host, u32 ocr) { |
1278dba16 mmc: initialize s... |
182 |
struct mmc_command cmd = {0}; |
da7fbe58d mmc: Separate out... |
183 184 |
int err; static const u8 test_pattern = 0xAA; |
af5171507 MMC core learns a... |
185 |
u8 result_pattern; |
da7fbe58d mmc: Separate out... |
186 187 188 189 190 191 192 193 |
/* * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND * before SD_APP_OP_COND. This command will harmlessly fail for * SD 1.0 cards. */ cmd.opcode = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; |
af5171507 MMC core learns a... |
194 |
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; |
da7fbe58d mmc: Separate out... |
195 196 |
err = mmc_wait_for_cmd(host, &cmd, 0); |
17b0429dd mmc: remove custo... |
197 |
if (err) |
da7fbe58d mmc: Separate out... |
198 |
return err; |
af5171507 MMC core learns a... |
199 200 201 202 203 204 |
if (mmc_host_is_spi(host)) result_pattern = cmd.resp[1] & 0xFF; else result_pattern = cmd.resp[0] & 0xFF; if (result_pattern != test_pattern) |
17b0429dd mmc: remove custo... |
205 |
return -EIO; |
da7fbe58d mmc: Separate out... |
206 |
|
17b0429dd mmc: remove custo... |
207 |
return 0; |
da7fbe58d mmc: Separate out... |
208 209 210 211 212 |
} int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) { int err; |
1278dba16 mmc: initialize s... |
213 |
struct mmc_command cmd = {0}; |
da7fbe58d mmc: Separate out... |
214 215 216 |
BUG_ON(!host); BUG_ON(!rca); |
da7fbe58d mmc: Separate out... |
217 218 219 220 221 |
cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); |
17b0429dd mmc: remove custo... |
222 |
if (err) |
da7fbe58d mmc: Separate out... |
223 224 225 |
return err; *rca = cmd.resp[0] >> 16; |
17b0429dd mmc: remove custo... |
226 |
return 0; |
da7fbe58d mmc: Separate out... |
227 228 229 230 231 |
} int mmc_app_send_scr(struct mmc_card *card, u32 *scr) { int err; |
ad5fd9728 mmc: fix integer ... |
232 |
struct mmc_request mrq = {NULL}; |
1278dba16 mmc: initialize s... |
233 |
struct mmc_command cmd = {0}; |
a61ad2b49 mmc: initialize s... |
234 |
struct mmc_data data = {0}; |
da7fbe58d mmc: Separate out... |
235 |
struct scatterlist sg; |
4f665cb61 mmc: fix mmc_app_... |
236 |
void *data_buf; |
da7fbe58d mmc: Separate out... |
237 238 239 240 |
BUG_ON(!card); BUG_ON(!card->host); BUG_ON(!scr); |
af5171507 MMC core learns a... |
241 |
/* NOTE: caller guarantees scr is heap-allocated */ |
da7fbe58d mmc: Separate out... |
242 |
err = mmc_app_cmd(card->host, card); |
17b0429dd mmc: remove custo... |
243 |
if (err) |
da7fbe58d mmc: Separate out... |
244 |
return err; |
4f665cb61 mmc: fix mmc_app_... |
245 246 247 248 249 250 |
/* dma onto stack is unsafe/nonportable, but callers to this * routine normally provide temporary on-stack buffers ... */ data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL); if (data_buf == NULL) return -ENOMEM; |
da7fbe58d mmc: Separate out... |
251 252 253 254 255 |
mrq.cmd = &cmd; mrq.data = &data; cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; |
af5171507 MMC core learns a... |
256 |
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
da7fbe58d mmc: Separate out... |
257 258 259 260 261 262 |
data.blksz = 8; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; |
4f665cb61 mmc: fix mmc_app_... |
263 |
sg_init_one(&sg, data_buf, 8); |
da7fbe58d mmc: Separate out... |
264 |
|
b146d26a6 mmc: mmc_set_data... |
265 |
mmc_set_data_timeout(&data, card); |
da7fbe58d mmc: Separate out... |
266 267 |
mmc_wait_for_req(card->host, &mrq); |
4f665cb61 mmc: fix mmc_app_... |
268 269 |
memcpy(scr, data_buf, sizeof(card->raw_scr)); kfree(data_buf); |
17b0429dd mmc: remove custo... |
270 |
if (cmd.error) |
da7fbe58d mmc: Separate out... |
271 |
return cmd.error; |
17b0429dd mmc: remove custo... |
272 |
if (data.error) |
da7fbe58d mmc: Separate out... |
273 |
return data.error; |
1fa8dd146 mmc: use common b... |
274 275 |
scr[0] = be32_to_cpu(scr[0]); scr[1] = be32_to_cpu(scr[1]); |
da7fbe58d mmc: Separate out... |
276 |
|
17b0429dd mmc: remove custo... |
277 |
return 0; |
da7fbe58d mmc: Separate out... |
278 279 280 281 282 |
} int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp) { |
ad5fd9728 mmc: fix integer ... |
283 |
struct mmc_request mrq = {NULL}; |
1278dba16 mmc: initialize s... |
284 |
struct mmc_command cmd = {0}; |
a61ad2b49 mmc: initialize s... |
285 |
struct mmc_data data = {0}; |
da7fbe58d mmc: Separate out... |
286 287 288 289 |
struct scatterlist sg; BUG_ON(!card); BUG_ON(!card->host); |
af5171507 MMC core learns a... |
290 |
/* NOTE: caller guarantees resp is heap-allocated */ |
da7fbe58d mmc: Separate out... |
291 292 |
mode = !!mode; value &= 0xF; |
da7fbe58d mmc: Separate out... |
293 294 295 296 297 298 299 |
mrq.cmd = &cmd; mrq.data = &data; cmd.opcode = SD_SWITCH; cmd.arg = mode << 31 | 0x00FFFFFF; cmd.arg &= ~(0xF << (group * 4)); cmd.arg |= value << (group * 4); |
af5171507 MMC core learns a... |
300 |
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
da7fbe58d mmc: Separate out... |
301 302 303 304 305 306 307 308 |
data.blksz = 64; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; sg_init_one(&sg, resp, 64); |
b146d26a6 mmc: mmc_set_data... |
309 |
mmc_set_data_timeout(&data, card); |
da7fbe58d mmc: Separate out... |
310 311 |
mmc_wait_for_req(card->host, &mrq); |
17b0429dd mmc: remove custo... |
312 |
if (cmd.error) |
da7fbe58d mmc: Separate out... |
313 |
return cmd.error; |
17b0429dd mmc: remove custo... |
314 |
if (data.error) |
da7fbe58d mmc: Separate out... |
315 |
return data.error; |
17b0429dd mmc: remove custo... |
316 |
return 0; |
da7fbe58d mmc: Separate out... |
317 |
} |
dfe86cba7 mmc: add erase, s... |
318 319 320 |
int mmc_app_sd_status(struct mmc_card *card, void *ssr) { int err; |
ad5fd9728 mmc: fix integer ... |
321 |
struct mmc_request mrq = {NULL}; |
1278dba16 mmc: initialize s... |
322 |
struct mmc_command cmd = {0}; |
a61ad2b49 mmc: initialize s... |
323 |
struct mmc_data data = {0}; |
dfe86cba7 mmc: add erase, s... |
324 325 326 327 328 329 330 331 332 333 334 |
struct scatterlist sg; BUG_ON(!card); BUG_ON(!card->host); BUG_ON(!ssr); /* NOTE: caller guarantees ssr is heap-allocated */ err = mmc_app_cmd(card->host, card); if (err) return err; |
dfe86cba7 mmc: add erase, s... |
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
mrq.cmd = &cmd; mrq.data = &data; cmd.opcode = SD_APP_SD_STATUS; cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC; data.blksz = 64; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; sg_init_one(&sg, ssr, 64); mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); if (cmd.error) return cmd.error; if (data.error) return data.error; return 0; } |