Jelajahi Sumber

sdio: read and decode interesting parts of the CCCR

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Pierre Ossman 18 tahun lalu
induk
melakukan
35c66c1908
2 mengubah file dengan 74 tambahan dan 0 penghapusan
  1. 63 0
      drivers/mmc/core/sdio.c
  2. 11 0
      include/linux/mmc/card.h

+ 63 - 0
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.
  */
@@ -180,6 +236,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
 	if (err)
 		goto remove;
 
+	/*
+	 * Read the common registers.
+	 */
+	err = sdio_read_cccr(card);
+	if (err)
+		goto remove;
+
 	/*
 	 * Initialize (but don't add) all present functions.
 	 */

+ 11 - 0
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) */
 };