]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/mmc/core/sdio.c
mmc: detect SDIO cards
[net-next-2.6.git] / drivers / mmc / core / sdio.c
CommitLineData
5c4e6f13
PO
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 */
26static 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 */
38static 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
64static 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 */
73int 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
162reclaim_host:
163 mmc_claim_host(host);
164free_card:
165 mmc_remove_card(card);
166 host->card = NULL;
167err:
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