aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/sdio.c
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-05-26 07:48:18 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 13:45:31 -0400
commite29a7d73f4277eb92aa64e17017dea33460828ef (patch)
tree0b8cfe6d145f41c43f86b475fff86627a305af1e /drivers/mmc/core/sdio.c
parentb2bcc798bbb482b2909801280f3c4aff8cbbf5be (diff)
mmc: basic SDIO device model
Add the sdio bus type and basic device handling. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/sdio.c')
-rw-r--r--drivers/mmc/core/sdio.c72
1 files changed, 63 insertions, 9 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index ac0dd68df8e7..444328581cec 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -13,21 +13,49 @@
13 13
14#include <linux/mmc/host.h> 14#include <linux/mmc/host.h>
15#include <linux/mmc/card.h> 15#include <linux/mmc/card.h>
16#include <linux/mmc/sdio_func.h>
16 17
17#include "core.h" 18#include "core.h"
18#include "bus.h" 19#include "bus.h"
20#include "sdio_bus.h"
19#include "mmc_ops.h" 21#include "mmc_ops.h"
20#include "sd_ops.h" 22#include "sd_ops.h"
21#include "sdio_ops.h" 23#include "sdio_ops.h"
22 24
25static int sdio_init_func(struct mmc_card *card, unsigned int fn)
26{
27 struct sdio_func *func;
28
29 BUG_ON(fn > SDIO_MAX_FUNCS);
30
31 func = sdio_alloc_func(card);
32 if (IS_ERR(func))
33 return PTR_ERR(func);
34
35 func->num = fn;
36
37 card->sdio_func[fn - 1] = func;
38
39 return 0;
40}
41
23/* 42/*
24 * Host is being removed. Free up the current card. 43 * Host is being removed. Free up the current card.
25 */ 44 */
26static void mmc_sdio_remove(struct mmc_host *host) 45static void mmc_sdio_remove(struct mmc_host *host)
27{ 46{
47 int i;
48
28 BUG_ON(!host); 49 BUG_ON(!host);
29 BUG_ON(!host->card); 50 BUG_ON(!host->card);
30 51
52 for (i = 0;i < host->card->sdio_funcs;i++) {
53 if (host->card->sdio_func[i]) {
54 sdio_remove_func(host->card->sdio_func[i]);
55 host->card->sdio_func[i] = NULL;
56 }
57 }
58
31 mmc_remove_card(host->card); 59 mmc_remove_card(host->card);
32 host->card = NULL; 60 host->card = NULL;
33} 61}
@@ -73,7 +101,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
73int mmc_attach_sdio(struct mmc_host *host, u32 ocr) 101int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
74{ 102{
75 int err; 103 int err;
76 int funcs; 104 int i, funcs;
77 struct mmc_card *card; 105 struct mmc_card *card;
78 106
79 BUG_ON(!host); 107 BUG_ON(!host);
@@ -132,13 +160,16 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
132 } 160 }
133 161
134 card->type = MMC_TYPE_SDIO; 162 card->type = MMC_TYPE_SDIO;
163 card->sdio_funcs = funcs;
164
165 host->card = card;
135 166
136 /* 167 /*
137 * Set card RCA. 168 * Set card RCA.
138 */ 169 */
139 err = mmc_send_relative_addr(host, &card->rca); 170 err = mmc_send_relative_addr(host, &card->rca);
140 if (err) 171 if (err)
141 goto free_card; 172 goto remove;
142 173
143 mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); 174 mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
144 175
@@ -147,23 +178,46 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
147 */ 178 */
148 err = mmc_select_card(card); 179 err = mmc_select_card(card);
149 if (err) 180 if (err)
150 goto free_card; 181 goto remove;
151 182
152 host->card = card; 183 /*
184 * Initialize (but don't add) all present functions.
185 */
186 for (i = 0;i < funcs;i++) {
187 err = sdio_init_func(host->card, i + 1);
188 if (err)
189 goto remove;
190 }
153 191
154 mmc_release_host(host); 192 mmc_release_host(host);
155 193
194 /*
195 * First add the card to the driver model...
196 */
156 err = mmc_add_card(host->card); 197 err = mmc_add_card(host->card);
157 if (err) 198 if (err)
158 goto reclaim_host; 199 goto remove_added;
200
201 /*
202 * ...then the SDIO functions.
203 */
204 for (i = 0;i < funcs;i++) {
205 err = sdio_add_func(host->card->sdio_func[i]);
206 if (err)
207 goto remove_added;
208 }
159 209
160 return 0; 210 return 0;
161 211
162reclaim_host: 212
213remove_added:
214 /* Remove without lock if the device has been added. */
215 mmc_sdio_remove(host);
163 mmc_claim_host(host); 216 mmc_claim_host(host);
164free_card: 217remove:
165 mmc_remove_card(card); 218 /* And with lock if it hasn't been added. */
166 host->card = NULL; 219 if (host->card)
220 mmc_sdio_remove(host);
167err: 221err:
168 mmc_detach_bus(host); 222 mmc_detach_bus(host);
169 mmc_release_host(host); 223 mmc_release_host(host);