Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sdio_ops.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/mmc/sdio_ops.c
3  *
4  * Copyright 2006-2007 Pierre Ossman
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  */
11 
12 #include <linux/scatterlist.h>
13 
14 #include <linux/mmc/host.h>
15 #include <linux/mmc/card.h>
16 #include <linux/mmc/mmc.h>
17 #include <linux/mmc/sdio.h>
18 
19 #include "core.h"
20 #include "sdio_ops.h"
21 
22 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
23 {
24  struct mmc_command cmd = {0};
25  int i, err = 0;
26 
27  BUG_ON(!host);
28 
30  cmd.arg = ocr;
32 
33  for (i = 100; i; i--) {
34  err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
35  if (err)
36  break;
37 
38  /* if we're just probing, do a single pass */
39  if (ocr == 0)
40  break;
41 
42  /* otherwise wait until reset completes */
43  if (mmc_host_is_spi(host)) {
44  /*
45  * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
46  * an initialized card under SPI, but some cards
47  * (Marvell's) only behave when looking at this
48  * one.
49  */
50  if (cmd.resp[1] & MMC_CARD_BUSY)
51  break;
52  } else {
53  if (cmd.resp[0] & MMC_CARD_BUSY)
54  break;
55  }
56 
57  err = -ETIMEDOUT;
58 
59  mmc_delay(10);
60  }
61 
62  if (rocr)
63  *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
64 
65  return err;
66 }
67 
68 static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
69  unsigned addr, u8 in, u8 *out)
70 {
71  struct mmc_command cmd = {0};
72  int err;
73 
74  BUG_ON(!host);
75  BUG_ON(fn > 7);
76 
77  /* sanity check */
78  if (addr & ~0x1FFFF)
79  return -EINVAL;
80 
81  cmd.opcode = SD_IO_RW_DIRECT;
82  cmd.arg = write ? 0x80000000 : 0x00000000;
83  cmd.arg |= fn << 28;
84  cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
85  cmd.arg |= addr << 9;
86  cmd.arg |= in;
88 
89  err = mmc_wait_for_cmd(host, &cmd, 0);
90  if (err)
91  return err;
92 
93  if (mmc_host_is_spi(host)) {
94  /* host driver already reported errors */
95  } else {
96  if (cmd.resp[0] & R5_ERROR)
97  return -EIO;
98  if (cmd.resp[0] & R5_FUNCTION_NUMBER)
99  return -EINVAL;
100  if (cmd.resp[0] & R5_OUT_OF_RANGE)
101  return -ERANGE;
102  }
103 
104  if (out) {
105  if (mmc_host_is_spi(host))
106  *out = (cmd.resp[0] >> 8) & 0xFF;
107  else
108  *out = cmd.resp[0] & 0xFF;
109  }
110 
111  return 0;
112 }
113 
114 int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
115  unsigned addr, u8 in, u8 *out)
116 {
117  BUG_ON(!card);
118  return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
119 }
120 
121 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
122  unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
123 {
124  struct mmc_request mrq = {NULL};
125  struct mmc_command cmd = {0};
126  struct mmc_data data = {0};
127  struct scatterlist sg;
128 
129  BUG_ON(!card);
130  BUG_ON(fn > 7);
131  WARN_ON(blksz == 0);
132 
133  /* sanity check */
134  if (addr & ~0x1FFFF)
135  return -EINVAL;
136 
137  mrq.cmd = &cmd;
138  mrq.data = &data;
139 
141  cmd.arg = write ? 0x80000000 : 0x00000000;
142  cmd.arg |= fn << 28;
143  cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
144  cmd.arg |= addr << 9;
145  if (blocks == 0)
146  cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
147  else
148  cmd.arg |= 0x08000000 | blocks; /* block mode */
150 
151  data.blksz = blksz;
152  /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
153  data.blocks = blocks ? blocks : 1;
154  data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
155  data.sg = &sg;
156  data.sg_len = 1;
157 
158  sg_init_one(&sg, buf, data.blksz * data.blocks);
159 
160  mmc_set_data_timeout(&data, card);
161 
162  mmc_wait_for_req(card->host, &mrq);
163 
164  if (cmd.error)
165  return cmd.error;
166  if (data.error)
167  return data.error;
168 
169  if (mmc_host_is_spi(card->host)) {
170  /* host driver already reported errors */
171  } else {
172  if (cmd.resp[0] & R5_ERROR)
173  return -EIO;
174  if (cmd.resp[0] & R5_FUNCTION_NUMBER)
175  return -EINVAL;
176  if (cmd.resp[0] & R5_OUT_OF_RANGE)
177  return -ERANGE;
178  }
179 
180  return 0;
181 }
182 
183 int sdio_reset(struct mmc_host *host)
184 {
185  int ret;
186  u8 abort;
187 
188  /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
189 
190  ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
191  if (ret)
192  abort = 0x08;
193  else
194  abort |= 0x08;
195 
196  ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
197  return ret;
198 }
199