summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-06-11 20:25:43 +0200
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 20:12:18 +0200
commit35c66c19088bddb11110c124bad8abd4441a8421 (patch)
tree54f62d67396b50716945d7ef321097715bcc3365 /drivers/mmc/core
parentfa64efa1f2a0672767ad0753a6e4bfa4bcc77b87 (diff)
sdio: read and decode interesting parts of the CCCR
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/sdio.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 444328581ce..7ce3e3104d2 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++) {