diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-06-11 20:25:43 +0200 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 20:12:18 +0200 |
commit | 35c66c19088bddb11110c124bad8abd4441a8421 (patch) | |
tree | 54f62d67396b50716945d7ef321097715bcc3365 | |
parent | fa64efa1f2a0672767ad0753a6e4bfa4bcc77b87 (diff) | |
download | op-kernel-dev-35c66c19088bddb11110c124bad8abd4441a8421.zip op-kernel-dev-35c66c19088bddb11110c124bad8abd4441a8421.tar.gz |
sdio: read and decode interesting parts of the CCCR
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r-- | drivers/mmc/core/sdio.c | 63 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 11 |
2 files changed, 74 insertions, 0 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 4443285..7ce3e31 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -13,6 +13,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include "core.h" @@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) return 0; } +static int sdio_read_cccr(struct mmc_card *card) +{ + int ret; + int cccr_vsn; + unsigned char data; + + memset(&card->cccr, 0, sizeof(struct sdio_cccr)); + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); + if (ret) + goto out; + + cccr_vsn = data & 0x0f; + + if (cccr_vsn > SDIO_CCCR_REV_1_20) { + printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", + mmc_hostname(card->host), cccr_vsn); + return -EINVAL; + } + + card->cccr.sdio_vsn = (data & 0xf0) >> 4; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); + if (ret) + goto out; + + if (data & SDIO_CCCR_CAP_SMB) + card->cccr.multi_block = 1; + if (data & SDIO_CCCR_CAP_LSC) + card->cccr.low_speed = 1; + if (data & SDIO_CCCR_CAP_4BLS) + card->cccr.wide_bus = 1; + + if (cccr_vsn >= SDIO_CCCR_REV_1_10) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); + if (ret) + goto out; + + if (data & SDIO_POWER_SMPC) + card->cccr.high_power = 1; + } + + if (cccr_vsn >= SDIO_CCCR_REV_1_20) { + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); + if (ret) + goto out; + + if (data & SDIO_SPEED_SHS) + card->cccr.high_speed = 1; + } + +out: + return ret; +} + /* * Host is being removed. Free up the current card. */ @@ -181,6 +237,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) goto remove; /* + * Read the common registers. + */ + err = sdio_read_cccr(card); + if (err) + goto remove; + + /* * Initialize (but don't add) all present functions. */ for (i = 0;i < funcs;i++) { diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 9f5f744..520d9d2 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -55,6 +55,16 @@ struct sd_switch_caps { unsigned int hs_max_dtr; }; +struct sdio_cccr { + unsigned int sdio_vsn; + unsigned int sd_vsn; + unsigned int multi_block:1, + low_speed:1, + wide_bus:1, + high_power:1, + high_speed:1; +}; + struct mmc_host; struct sdio_func; @@ -87,6 +97,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ unsigned int sdio_funcs; /* number of SDIO functions */ + struct sdio_cccr cccr; /* common card info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; |