aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/sdio.c63
-rw-r--r--include/linux/mmc/card.h11
2 files changed, 74 insertions, 0 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 444328581cec..7ce3e3104d21 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -13,6 +13,7 @@
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.h>
16#include <linux/mmc/sdio_func.h> 17#include <linux/mmc/sdio_func.h>
17 18
18#include "core.h" 19#include "core.h"
@@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
39 return 0; 40 return 0;
40} 41}
41 42
43static int sdio_read_cccr(struct mmc_card *card)
44{
45 int ret;
46 int cccr_vsn;
47 unsigned char data;
48
49 memset(&card->cccr, 0, sizeof(struct sdio_cccr));
50
51 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
52 if (ret)
53 goto out;
54
55 cccr_vsn = data & 0x0f;
56
57 if (cccr_vsn > SDIO_CCCR_REV_1_20) {
58 printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n",
59 mmc_hostname(card->host), cccr_vsn);
60 return -EINVAL;
61 }
62
63 card->cccr.sdio_vsn = (data & 0xf0) >> 4;
64
65 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
66 if (ret)
67 goto out;
68
69 if (data & SDIO_CCCR_CAP_SMB)
70 card->cccr.multi_block = 1;
71 if (data & SDIO_CCCR_CAP_LSC)
72 card->cccr.low_speed = 1;
73 if (data & SDIO_CCCR_CAP_4BLS)
74 card->cccr.wide_bus = 1;
75
76 if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
77 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
78 if (ret)
79 goto out;
80
81 if (data & SDIO_POWER_SMPC)
82 card->cccr.high_power = 1;
83 }
84
85 if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
86 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
87 if (ret)
88 goto out;
89
90 if (data & SDIO_SPEED_SHS)
91 card->cccr.high_speed = 1;
92 }
93
94out:
95 return ret;
96}
97
42/* 98/*
43 * Host is being removed. Free up the current card. 99 * Host is being removed. Free up the current card.
44 */ 100 */
@@ -181,6 +237,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
181 goto remove; 237 goto remove;
182 238
183 /* 239 /*
240 * Read the common registers.
241 */
242 err = sdio_read_cccr(card);
243 if (err)
244 goto remove;
245
246 /*
184 * Initialize (but don't add) all present functions. 247 * Initialize (but don't add) all present functions.
185 */ 248 */
186 for (i = 0;i < funcs;i++) { 249 for (i = 0;i < funcs;i++) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9f5f74482d98..520d9d29b3b2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -55,6 +55,16 @@ struct sd_switch_caps {
55 unsigned int hs_max_dtr; 55 unsigned int hs_max_dtr;
56}; 56};
57 57
58struct sdio_cccr {
59 unsigned int sdio_vsn;
60 unsigned int sd_vsn;
61 unsigned int multi_block:1,
62 low_speed:1,
63 wide_bus:1,
64 high_power:1,
65 high_speed:1;
66};
67
58struct mmc_host; 68struct mmc_host;
59struct sdio_func; 69struct sdio_func;
60 70
@@ -87,6 +97,7 @@ struct mmc_card {
87 struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ 97 struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
88 98
89 unsigned int sdio_funcs; /* number of SDIO functions */ 99 unsigned int sdio_funcs; /* number of SDIO functions */
100 struct sdio_cccr cccr; /* common card info */
90 struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ 101 struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
91}; 102};
92 103