]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/mmc/core/sdio.c
mmc: detect SDIO cards
[linux-2.6-omap-h63xx.git] / drivers / mmc / core / sdio.c
1 /*
2  *  linux/drivers/mmc/sdio.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/err.h>
13
14 #include <linux/mmc/host.h>
15 #include <linux/mmc/card.h>
16
17 #include "core.h"
18 #include "bus.h"
19 #include "mmc_ops.h"
20 #include "sd_ops.h"
21 #include "sdio_ops.h"
22
23 /*
24  * Host is being removed. Free up the current card.
25  */
26 static void mmc_sdio_remove(struct mmc_host *host)
27 {
28         BUG_ON(!host);
29         BUG_ON(!host->card);
30
31         mmc_remove_card(host->card);
32         host->card = NULL;
33 }
34
35 /*
36  * Card detection callback from host.
37  */
38 static void mmc_sdio_detect(struct mmc_host *host)
39 {
40         int err;
41
42         BUG_ON(!host);
43         BUG_ON(!host->card);
44
45         mmc_claim_host(host);
46
47         /*
48          * Just check if our card has been removed.
49          */
50         err = mmc_select_card(host->card);
51
52         mmc_release_host(host);
53
54         if (err) {
55                 mmc_sdio_remove(host);
56
57                 mmc_claim_host(host);
58                 mmc_detach_bus(host);
59                 mmc_release_host(host);
60         }
61 }
62
63
64 static const struct mmc_bus_ops mmc_sdio_ops = {
65         .remove = mmc_sdio_remove,
66         .detect = mmc_sdio_detect,
67 };
68
69
70 /*
71  * Starting point for SDIO card init.
72  */
73 int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
74 {
75         int err;
76         int funcs;
77         struct mmc_card *card;
78
79         BUG_ON(!host);
80         BUG_ON(!host->claimed);
81
82         mmc_attach_bus(host, &mmc_sdio_ops);
83
84         /*
85          * Sanity check the voltages that the card claims to
86          * support.
87          */
88         if (ocr & 0x7F) {
89                 printk(KERN_WARNING "%s: card claims to support voltages "
90                        "below the defined range. These will be ignored.\n",
91                        mmc_hostname(host));
92                 ocr &= ~0x7F;
93         }
94
95         if (ocr & MMC_VDD_165_195) {
96                 printk(KERN_WARNING "%s: SDIO card claims to support the "
97                        "incompletely defined 'low voltage range'. This "
98                        "will be ignored.\n", mmc_hostname(host));
99                 ocr &= ~MMC_VDD_165_195;
100         }
101
102         host->ocr = mmc_select_voltage(host, ocr);
103
104         /*
105          * Can we support the voltage(s) of the card(s)?
106          */
107         if (!host->ocr) {
108                 err = -EINVAL;
109                 goto err;
110         }
111
112         /*
113          * Inform the card of the voltage
114          */
115         err = mmc_send_io_op_cond(host, host->ocr, &ocr);
116         if (err)
117                 goto err;
118
119         /*
120          * The number of functions on the card is encoded inside
121          * the ocr.
122          */
123         funcs = (ocr & 0x70000000) >> 28;
124
125         /*
126          * Allocate card structure.
127          */
128         card = mmc_alloc_card(host);
129         if (IS_ERR(card)) {
130                 err = PTR_ERR(card);
131                 goto err;
132         }
133
134         card->type = MMC_TYPE_SDIO;
135
136         /*
137          * Set card RCA.
138          */
139         err = mmc_send_relative_addr(host, &card->rca);
140         if (err)
141                 goto free_card;
142
143         mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
144
145         /*
146          * Select card, as all following commands rely on that.
147          */
148         err = mmc_select_card(card);
149         if (err)
150                 goto free_card;
151
152         host->card = card;
153
154         mmc_release_host(host);
155
156         err = mmc_add_card(host->card);
157         if (err)
158                 goto reclaim_host;
159
160         return 0;
161
162 reclaim_host:
163         mmc_claim_host(host);
164 free_card:
165         mmc_remove_card(card);
166         host->card = NULL;
167 err:
168         mmc_detach_bus(host);
169         mmc_release_host(host);
170
171         printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
172                 mmc_hostname(host), err);
173
174         return err;
175 }
176