Discussion:
[PATCH 0/3] add non-standard SDIO card support
Grazvydas Ignotas
2010-06-29 13:49:22 UTC
Permalink
This is my attempt to make SDIO interfaced TI WL1251 wifi chip usable
on mainline kernels. It's driver has already been merged several releases
back, but the problem is current SDIO core can't detect the card because
it's not following SDIO standards and does not have any required SDIO
registers. Currenty attempting to use this chip only results in several
pages of complains about invalid register data from SDIO core.
WL1251 is used on various HTC devices and Pandora handheld at least.

People wanting to use this are forced to use forked trees or patches.
My solution to this problem is to add new MMC quirk that will tell SDIO
core not to access any SDIO registers and rely on host's init_card
callback instead, which is now responsible for filling card related
structures for SDIO core to function. Patches 2 and 3 set up the card
for pandora, similar method could be used for MSM too.

Only patches 2,3 depend on each other, so patch 1 can be merged separately.

Grazvydas Ignotas (3):
sdio: allow non-standard SDIO cards
omap_hsmmc: add init_card pass-through callback
omap: pandora: pass information about wl1251 to SDIO core

arch/arm/mach-omap2/board-omap3pandora.c | 16 +++++++++++++
arch/arm/mach-omap2/hsmmc.c | 1 +
arch/arm/mach-omap2/hsmmc.h | 4 +++
arch/arm/plat-omap/include/plat/mmc.h | 2 +
drivers/mmc/core/sdio.c | 36 +++++++++++++++++++++++++-----
drivers/mmc/host/omap_hsmmc.c | 10 ++++++++
include/linux/mmc/card.h | 2 +
7 files changed, 65 insertions(+), 6 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grazvydas Ignotas
2010-06-29 13:49:23 UTC
Permalink
There are some chips (like TI WL12xx series) that can be interfaced
over SDIO but don't support the SDIO specification, meaning that they
are missing CIA (Common I/O Area) with all it's registers. Current
Linux SDIO implementation relies on those registers to identify and
configure the card, so non-standard cards can not function and cause
lots of warnings from the core when it reads invalid data from
non-existent registers.

After this patch, init_card() host callback can now set new quirk
MMC_QUIRK_NONSTD_SDIO, which means that SDIO core should not try to
access any standard SDIO registers and rely on init_card() to fill all
SDIO structures instead. As those cards are usually embedded chips,
all the required information can be obtained from machine board files
by the host driver when it's called through init_card() callback.

Signed-off-by: Grazvydas Ignotas <***@gmail.com>
---
drivers/mmc/core/sdio.c | 36 ++++++++++++++++++++++++++++++------
include/linux/mmc/card.h | 2 ++
2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index b9dee28..cb66833 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -62,13 +62,19 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)

func->num = fn;

- ret = sdio_read_fbr(func);
- if (ret)
- goto fail;
+ if (!(card->quirks & MMC_QUIRK_NONSTD_SDIO)) {
+ ret = sdio_read_fbr(func);
+ if (ret)
+ goto fail;

- ret = sdio_read_func_cis(func);
- if (ret)
- goto fail;
+ ret = sdio_read_func_cis(func);
+ if (ret)
+ goto fail;
+ } else {
+ func->vendor = func->card->cis.vendor;
+ func->device = func->card->cis.device;
+ func->max_blksize = func->card->cis.blksize;
+ }

card->sdio_func[fn - 1] = func;

@@ -321,6 +327,23 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto remove;
}

+ if (card->quirks & MMC_QUIRK_NONSTD_SDIO) {
+ /*
+ * This is non-standard SDIO device, meaning it doesn't
+ * have any CIA (Common I/O area) registers present.
+ * It's host's responsibility to fill cccr and cis
+ * structures in init_card().
+ */
+ mmc_set_clock(host, card->cis.max_dtr);
+
+ if (card->cccr.high_speed) {
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+ }
+
+ goto finish;
+ }
+
/*
* Read the common registers.
*/
@@ -376,6 +399,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
if (err)
goto remove;

+finish:
if (!oldcard)
host->card = card;
return 0;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d02d2c6..cbc745c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -101,6 +101,8 @@ struct mmc_card {
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
/* for byte mode */
+#define MMC_QUIRK_NONSTD_SDIO (1<<2) /* non-standard SDIO card attached */
+ /* (missing CIA registers) */

u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
--
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grazvydas Ignotas
2010-06-29 13:49:24 UTC
Permalink
This will allow us to set up special cards in machine drivers just
after they are detected by MMC core.

Signed-off-by: Grazvydas Ignotas <***@gmail.com>
---
arch/arm/plat-omap/include/plat/mmc.h | 2 ++
drivers/mmc/host/omap_hsmmc.c | 10 ++++++++++
2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index c835f1e..9b89ec6 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -122,6 +122,8 @@ struct omap_mmc_platform_data {
/* Call back after enabling / disabling regulators */
void (*after_set_reg)(struct device *dev, int slot,
int power_on, int vdd);
+ /* if we have special card, init it using this callback */
+ void (*init_card)(struct mmc_card *card);

/* return MMC cover switch state, can be NULL if not supported.
*
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index b032828..e8eb39e 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1598,6 +1598,14 @@ static int omap_hsmmc_get_ro(struct mmc_host *mmc)
return mmc_slot(host).get_ro(host->dev, 0);
}

+static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct omap_hsmmc_host *host = mmc_priv(mmc);
+
+ if (mmc_slot(host).init_card)
+ mmc_slot(host).init_card(card);
+}
+
static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
{
u32 hctl, capa, value;
@@ -1869,6 +1877,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
.set_ios = omap_hsmmc_set_ios,
.get_cd = omap_hsmmc_get_cd,
.get_ro = omap_hsmmc_get_ro,
+ .init_card = omap_hsmmc_init_card,
/* NYET -- enable_sdio_irq */
};

@@ -1879,6 +1888,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
.set_ios = omap_hsmmc_set_ios,
.get_cd = omap_hsmmc_get_cd,
.get_ro = omap_hsmmc_get_ro,
+ .init_card = omap_hsmmc_init_card,
/* NYET -- enable_sdio_irq */
};
--
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grazvydas Ignotas
2010-06-29 13:49:25 UTC
Permalink
Pandora has TI WL1251 attached on MMC3, which is non-standard SDIO chip.
Make use MMC_QUIRK_NONSTD_SDIO to tell SDIO core about it.

Signed-off-by: Grazvydas Ignotas <***@gmail.com>
---
arch/arm/mach-omap2/board-omap3pandora.c | 16 ++++++++++++++++
arch/arm/mach-omap2/hsmmc.c | 1 +
arch/arm/mach-omap2/hsmmc.h | 4 ++++
3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index db06dc9..ebbfb49 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -29,6 +29,7 @@
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/gpio_keys.h>
+#include <linux/mmc/card.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -227,6 +228,20 @@ static struct platform_device pandora_dss_device = {
},
};

+static void pandora_wl1251_init_card(struct mmc_card *card)
+{
+ /*
+ * We have TI wl1251 attached to MMC3. Pass this information to
+ * SDIO core because it can't be probed by normal methods.
+ */
+ card->quirks |= MMC_QUIRK_NONSTD_SDIO;
+ card->cccr.wide_bus = 1;
+ card->cis.vendor = 0x104c;
+ card->cis.device = 0x9066;
+ card->cis.blksize = 512;
+ card->cis.max_dtr = 20000000;
+}
+
static struct omap2_hsmmc_info omap3pandora_mmc[] = {
{
.mmc = 1,
@@ -248,6 +263,7 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
.wires = 4,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
+ .init_card = pandora_wl1251_init_card,
},
{} /* Terminator */
};
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 1ef54b0..c8f647b 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -268,6 +268,7 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
mmc->slots[0].gpio_wp = c->gpio_wp;

mmc->slots[0].remux = c->remux;
+ mmc->slots[0].init_card = c->init_card;

if (c->cover_only)
mmc->slots[0].cover = 1;
diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h
index 36f0ba8..1fe6f01 100644
--- a/arch/arm/mach-omap2/hsmmc.h
+++ b/arch/arm/mach-omap2/hsmmc.h
@@ -6,6 +6,8 @@
* published by the Free Software Foundation.
*/

+struct mmc_card;
+
struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */
u8 wires; /* 1/4/8 wires */
@@ -23,6 +25,8 @@ struct omap2_hsmmc_info {
int ocr_mask; /* temporary HACK */
/* Remux (pad configuation) when powering on/off */
void (*remux)(struct device *dev, int slot, int power_on);
+ /* init some special card */
+ void (*init_card)(struct mmc_card *card);
};

#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
--
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...