xref: /openbmc/linux/drivers/mmc/core/mmc_ops.c (revision 70f10482)
1da7fbe58SPierre Ossman /*
270f10482SPierre Ossman  *  linux/drivers/mmc/core/mmc_ops.h
3da7fbe58SPierre Ossman  *
4da7fbe58SPierre Ossman  *  Copyright 2006-2007 Pierre Ossman
5da7fbe58SPierre Ossman  *
6da7fbe58SPierre Ossman  * This program is free software; you can redistribute it and/or modify
7da7fbe58SPierre Ossman  * it under the terms of the GNU General Public License as published by
8da7fbe58SPierre Ossman  * the Free Software Foundation; either version 2 of the License, or (at
9da7fbe58SPierre Ossman  * your option) any later version.
10da7fbe58SPierre Ossman  */
11da7fbe58SPierre Ossman 
12da7fbe58SPierre Ossman #include <linux/types.h>
13da7fbe58SPierre Ossman #include <asm/scatterlist.h>
14da7fbe58SPierre Ossman #include <linux/scatterlist.h>
15da7fbe58SPierre Ossman 
16da7fbe58SPierre Ossman #include <linux/mmc/host.h>
17da7fbe58SPierre Ossman #include <linux/mmc/card.h>
18da7fbe58SPierre Ossman #include <linux/mmc/mmc.h>
19da7fbe58SPierre Ossman 
20da7fbe58SPierre Ossman #include "core.h"
21da7fbe58SPierre Ossman #include "mmc_ops.h"
22da7fbe58SPierre Ossman 
23da7fbe58SPierre Ossman static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
24da7fbe58SPierre Ossman {
25da7fbe58SPierre Ossman 	int err;
26da7fbe58SPierre Ossman 	struct mmc_command cmd;
27da7fbe58SPierre Ossman 
28da7fbe58SPierre Ossman 	BUG_ON(!host);
29da7fbe58SPierre Ossman 
30da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
31da7fbe58SPierre Ossman 
32da7fbe58SPierre Ossman 	cmd.opcode = MMC_SELECT_CARD;
33da7fbe58SPierre Ossman 
34da7fbe58SPierre Ossman 	if (card) {
35da7fbe58SPierre Ossman 		cmd.arg = card->rca << 16;
36da7fbe58SPierre Ossman 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
37da7fbe58SPierre Ossman 	} else {
38da7fbe58SPierre Ossman 		cmd.arg = 0;
39da7fbe58SPierre Ossman 		cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
40da7fbe58SPierre Ossman 	}
41da7fbe58SPierre Ossman 
42da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
43da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
44da7fbe58SPierre Ossman 		return err;
45da7fbe58SPierre Ossman 
46da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
47da7fbe58SPierre Ossman }
48da7fbe58SPierre Ossman 
49da7fbe58SPierre Ossman int mmc_select_card(struct mmc_card *card)
50da7fbe58SPierre Ossman {
51da7fbe58SPierre Ossman 	BUG_ON(!card);
52da7fbe58SPierre Ossman 
53da7fbe58SPierre Ossman 	return _mmc_select_card(card->host, card);
54da7fbe58SPierre Ossman }
55da7fbe58SPierre Ossman 
56da7fbe58SPierre Ossman int mmc_deselect_cards(struct mmc_host *host)
57da7fbe58SPierre Ossman {
58da7fbe58SPierre Ossman 	return _mmc_select_card(host, NULL);
59da7fbe58SPierre Ossman }
60da7fbe58SPierre Ossman 
61da7fbe58SPierre Ossman int mmc_go_idle(struct mmc_host *host)
62da7fbe58SPierre Ossman {
63da7fbe58SPierre Ossman 	int err;
64da7fbe58SPierre Ossman 	struct mmc_command cmd;
65da7fbe58SPierre Ossman 
66da7fbe58SPierre Ossman 	mmc_set_chip_select(host, MMC_CS_HIGH);
67da7fbe58SPierre Ossman 
68da7fbe58SPierre Ossman 	mmc_delay(1);
69da7fbe58SPierre Ossman 
70da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
71da7fbe58SPierre Ossman 
72da7fbe58SPierre Ossman 	cmd.opcode = MMC_GO_IDLE_STATE;
73da7fbe58SPierre Ossman 	cmd.arg = 0;
74da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
75da7fbe58SPierre Ossman 
76da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(host, &cmd, 0);
77da7fbe58SPierre Ossman 
78da7fbe58SPierre Ossman 	mmc_delay(1);
79da7fbe58SPierre Ossman 
80da7fbe58SPierre Ossman 	mmc_set_chip_select(host, MMC_CS_DONTCARE);
81da7fbe58SPierre Ossman 
82da7fbe58SPierre Ossman 	mmc_delay(1);
83da7fbe58SPierre Ossman 
84da7fbe58SPierre Ossman 	return err;
85da7fbe58SPierre Ossman }
86da7fbe58SPierre Ossman 
87da7fbe58SPierre Ossman int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
88da7fbe58SPierre Ossman {
89da7fbe58SPierre Ossman 	struct mmc_command cmd;
90da7fbe58SPierre Ossman 	int i, err = 0;
91da7fbe58SPierre Ossman 
92da7fbe58SPierre Ossman 	BUG_ON(!host);
93da7fbe58SPierre Ossman 
94da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
95da7fbe58SPierre Ossman 
96da7fbe58SPierre Ossman 	cmd.opcode = MMC_SEND_OP_COND;
97da7fbe58SPierre Ossman 	cmd.arg = ocr;
98da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
99da7fbe58SPierre Ossman 
100da7fbe58SPierre Ossman 	for (i = 100; i; i--) {
101da7fbe58SPierre Ossman 		err = mmc_wait_for_cmd(host, &cmd, 0);
102da7fbe58SPierre Ossman 		if (err != MMC_ERR_NONE)
103da7fbe58SPierre Ossman 			break;
104da7fbe58SPierre Ossman 
105da7fbe58SPierre Ossman 		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
106da7fbe58SPierre Ossman 			break;
107da7fbe58SPierre Ossman 
108da7fbe58SPierre Ossman 		err = MMC_ERR_TIMEOUT;
109da7fbe58SPierre Ossman 
110da7fbe58SPierre Ossman 		mmc_delay(10);
111da7fbe58SPierre Ossman 	}
112da7fbe58SPierre Ossman 
113da7fbe58SPierre Ossman 	if (rocr)
114da7fbe58SPierre Ossman 		*rocr = cmd.resp[0];
115da7fbe58SPierre Ossman 
116da7fbe58SPierre Ossman 	return err;
117da7fbe58SPierre Ossman }
118da7fbe58SPierre Ossman 
119da7fbe58SPierre Ossman int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
120da7fbe58SPierre Ossman {
121da7fbe58SPierre Ossman 	int err;
122da7fbe58SPierre Ossman 	struct mmc_command cmd;
123da7fbe58SPierre Ossman 
124da7fbe58SPierre Ossman 	BUG_ON(!host);
125da7fbe58SPierre Ossman 	BUG_ON(!cid);
126da7fbe58SPierre Ossman 
127da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
128da7fbe58SPierre Ossman 
129da7fbe58SPierre Ossman 	cmd.opcode = MMC_ALL_SEND_CID;
130da7fbe58SPierre Ossman 	cmd.arg = 0;
131da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
132da7fbe58SPierre Ossman 
133da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
134da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
135da7fbe58SPierre Ossman 		return err;
136da7fbe58SPierre Ossman 
137da7fbe58SPierre Ossman 	memcpy(cid, cmd.resp, sizeof(u32) * 4);
138da7fbe58SPierre Ossman 
139da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
140da7fbe58SPierre Ossman }
141da7fbe58SPierre Ossman 
142da7fbe58SPierre Ossman int mmc_set_relative_addr(struct mmc_card *card)
143da7fbe58SPierre Ossman {
144da7fbe58SPierre Ossman 	int err;
145da7fbe58SPierre Ossman 	struct mmc_command cmd;
146da7fbe58SPierre Ossman 
147da7fbe58SPierre Ossman 	BUG_ON(!card);
148da7fbe58SPierre Ossman 	BUG_ON(!card->host);
149da7fbe58SPierre Ossman 
150da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
151da7fbe58SPierre Ossman 
152da7fbe58SPierre Ossman 	cmd.opcode = MMC_SET_RELATIVE_ADDR;
153da7fbe58SPierre Ossman 	cmd.arg = card->rca << 16;
154da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
155da7fbe58SPierre Ossman 
156da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
157da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
158da7fbe58SPierre Ossman 		return err;
159da7fbe58SPierre Ossman 
160da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
161da7fbe58SPierre Ossman }
162da7fbe58SPierre Ossman 
163da7fbe58SPierre Ossman int mmc_send_csd(struct mmc_card *card, u32 *csd)
164da7fbe58SPierre Ossman {
165da7fbe58SPierre Ossman 	int err;
166da7fbe58SPierre Ossman 	struct mmc_command cmd;
167da7fbe58SPierre Ossman 
168da7fbe58SPierre Ossman 	BUG_ON(!card);
169da7fbe58SPierre Ossman 	BUG_ON(!card->host);
170da7fbe58SPierre Ossman 	BUG_ON(!csd);
171da7fbe58SPierre Ossman 
172da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
173da7fbe58SPierre Ossman 
174da7fbe58SPierre Ossman 	cmd.opcode = MMC_SEND_CSD;
175da7fbe58SPierre Ossman 	cmd.arg = card->rca << 16;
176da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
177da7fbe58SPierre Ossman 
178da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
179da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
180da7fbe58SPierre Ossman 		return err;
181da7fbe58SPierre Ossman 
182da7fbe58SPierre Ossman 	memcpy(csd, cmd.resp, sizeof(u32) * 4);
183da7fbe58SPierre Ossman 
184da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
185da7fbe58SPierre Ossman }
186da7fbe58SPierre Ossman 
187da7fbe58SPierre Ossman int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
188da7fbe58SPierre Ossman {
189da7fbe58SPierre Ossman 	struct mmc_request mrq;
190da7fbe58SPierre Ossman 	struct mmc_command cmd;
191da7fbe58SPierre Ossman 	struct mmc_data data;
192da7fbe58SPierre Ossman 	struct scatterlist sg;
193da7fbe58SPierre Ossman 
194da7fbe58SPierre Ossman 	BUG_ON(!card);
195da7fbe58SPierre Ossman 	BUG_ON(!card->host);
196da7fbe58SPierre Ossman 	BUG_ON(!ext_csd);
197da7fbe58SPierre Ossman 
198da7fbe58SPierre Ossman 	memset(&mrq, 0, sizeof(struct mmc_request));
199da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
200da7fbe58SPierre Ossman 	memset(&data, 0, sizeof(struct mmc_data));
201da7fbe58SPierre Ossman 
202da7fbe58SPierre Ossman 	mrq.cmd = &cmd;
203da7fbe58SPierre Ossman 	mrq.data = &data;
204da7fbe58SPierre Ossman 
205da7fbe58SPierre Ossman 	cmd.opcode = MMC_SEND_EXT_CSD;
206da7fbe58SPierre Ossman 	cmd.arg = 0;
207da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
208da7fbe58SPierre Ossman 
209da7fbe58SPierre Ossman 	data.blksz = 512;
210da7fbe58SPierre Ossman 	data.blocks = 1;
211da7fbe58SPierre Ossman 	data.flags = MMC_DATA_READ;
212da7fbe58SPierre Ossman 	data.sg = &sg;
213da7fbe58SPierre Ossman 	data.sg_len = 1;
214da7fbe58SPierre Ossman 
215da7fbe58SPierre Ossman 	sg_init_one(&sg, ext_csd, 512);
216da7fbe58SPierre Ossman 
217da7fbe58SPierre Ossman 	mmc_set_data_timeout(&data, card, 0);
218da7fbe58SPierre Ossman 
219da7fbe58SPierre Ossman 	mmc_wait_for_req(card->host, &mrq);
220da7fbe58SPierre Ossman 
221da7fbe58SPierre Ossman 	if (cmd.error != MMC_ERR_NONE)
222da7fbe58SPierre Ossman 		return cmd.error;
223da7fbe58SPierre Ossman 	if (data.error != MMC_ERR_NONE)
224da7fbe58SPierre Ossman 		return data.error;
225da7fbe58SPierre Ossman 
226da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
227da7fbe58SPierre Ossman }
228da7fbe58SPierre Ossman 
229da7fbe58SPierre Ossman int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
230da7fbe58SPierre Ossman {
231da7fbe58SPierre Ossman 	int err;
232da7fbe58SPierre Ossman 	struct mmc_command cmd;
233da7fbe58SPierre Ossman 
234da7fbe58SPierre Ossman 	BUG_ON(!card);
235da7fbe58SPierre Ossman 	BUG_ON(!card->host);
236da7fbe58SPierre Ossman 
237da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
238da7fbe58SPierre Ossman 
239da7fbe58SPierre Ossman 	cmd.opcode = MMC_SWITCH;
240da7fbe58SPierre Ossman 	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
241da7fbe58SPierre Ossman 		  (index << 16) |
242da7fbe58SPierre Ossman 		  (value << 8) |
243da7fbe58SPierre Ossman 		  set;
244da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
245da7fbe58SPierre Ossman 
246da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
247da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
248da7fbe58SPierre Ossman 		return err;
249da7fbe58SPierre Ossman 
250da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
251da7fbe58SPierre Ossman }
252da7fbe58SPierre Ossman 
253da7fbe58SPierre Ossman int mmc_send_status(struct mmc_card *card, u32 *status)
254da7fbe58SPierre Ossman {
255da7fbe58SPierre Ossman 	int err;
256da7fbe58SPierre Ossman 	struct mmc_command cmd;
257da7fbe58SPierre Ossman 
258da7fbe58SPierre Ossman 	BUG_ON(!card);
259da7fbe58SPierre Ossman 	BUG_ON(!card->host);
260da7fbe58SPierre Ossman 
261da7fbe58SPierre Ossman 	memset(&cmd, 0, sizeof(struct mmc_command));
262da7fbe58SPierre Ossman 
263da7fbe58SPierre Ossman 	cmd.opcode = MMC_SEND_STATUS;
264da7fbe58SPierre Ossman 	cmd.arg = card->rca << 16;
265da7fbe58SPierre Ossman 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
266da7fbe58SPierre Ossman 
267da7fbe58SPierre Ossman 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
268da7fbe58SPierre Ossman 	if (err != MMC_ERR_NONE)
269da7fbe58SPierre Ossman 		return err;
270da7fbe58SPierre Ossman 
271da7fbe58SPierre Ossman 	if (status)
272da7fbe58SPierre Ossman 		*status = cmd.resp[0];
273da7fbe58SPierre Ossman 
274da7fbe58SPierre Ossman 	return MMC_ERR_NONE;
275da7fbe58SPierre Ossman }
276da7fbe58SPierre Ossman 
277