diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-26 07:48:18 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 13:45:31 -0400 |
commit | e29a7d73f4277eb92aa64e17017dea33460828ef (patch) | |
tree | 0b8cfe6d145f41c43f86b475fff86627a305af1e /drivers/mmc/core/sdio.c | |
parent | b2bcc798bbb482b2909801280f3c4aff8cbbf5be (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.c | 72 |
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 | ||
25 | static 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 | */ |
26 | static void mmc_sdio_remove(struct mmc_host *host) | 45 | static 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 = { | |||
73 | int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | 101 | int 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 | ||
162 | reclaim_host: | 212 | |
213 | remove_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); |
164 | free_card: | 217 | remove: |
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); | ||
167 | err: | 221 | err: |
168 | mmc_detach_bus(host); | 222 | mmc_detach_bus(host); |
169 | mmc_release_host(host); | 223 | mmc_release_host(host); |