* [PATCH 1/5] SDIO: introduce API for special power management features
2010-02-09 20:29 [PATCH 0/5] SDIO support for "powered" suspend Nicolas Pitre
@ 2010-02-09 20:29 ` Nicolas Pitre
2010-02-11 20:32 ` Andrew Morton
2010-02-09 20:29 ` [PATCH 2/5] SDIO: sdhci support for suspend mode PM features Nicolas Pitre
` (3 subsequent siblings)
4 siblings, 1 reply; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-09 20:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
Some SDIO cards have the ability to keep on running autonomously when
the host system is suspended, and wake it up when needed. This however
requires that the host controller preserve power to the card, and
configure itself appropriately for wake-up.
There is however 4 layers of abstractions involved: the host controller
driver, the MMC core code, the SDIO card management code, and the actual
SDIO function driver. To make things simple and manageable, host drivers
must advertise their PM capabilities with a feature bitmask, then function
drivers can query and set those features from their suspend method.
Then each layer in the suspend call chain is expected to act upon those
bits accordingly.
Signed-off-by: Nicolas Pitre <nico@marvell.com>
---
drivers/mmc/core/core.c | 12 +++++++--
drivers/mmc/core/sdio_io.c | 49 +++++++++++++++++++++++++++++++++++++++++
include/linux/mmc/host.h | 5 ++++
include/linux/mmc/pm.h | 30 +++++++++++++++++++++++++
include/linux/mmc/sdio_func.h | 5 ++++
5 files changed, 98 insertions(+), 3 deletions(-)
create mode 100644 include/linux/mmc/pm.h
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 30acd52..1dc34a4 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1259,6 +1259,9 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
+ /* clear pm flags now and let card drivers set them as needed */
+ host->pm_flags = 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend)
@@ -1273,12 +1276,13 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_release_host(host);
+ host->pm_flags = 0;
err = 0;
}
}
mmc_bus_put(host);
- if (!err)
+ if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
mmc_power_off(host);
return err;
@@ -1296,8 +1300,10 @@ int mmc_resume_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
+ if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ }
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
if (err) {
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index f9aa8a7..ee25ffa 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -635,3 +635,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
*err_ret = ret;
}
EXPORT_SYMBOL_GPL(sdio_f0_writeb);
+
+/**
+ * sdio_get_host_pm_caps - get host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * REturns a capability bitmask corresponding to power management
+ * features supported by the host controller that the card function
+ * might rely upon during a system suspend. The host doesn't need
+ * to be claimed, nor the function active, for this information to be
+ * obtained.
+ */
+mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ return func->card->host->pm_caps;
+}
+EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
+
+/**
+ * sdio_set_host_pm_flags - set wanted host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * Set a capability bitmask corresponding to wanted host controller
+ * power management features for the upcoming suspend state.
+ * This must be called, if needed, each time the suspend method of
+ * the function driver is called, and must contain only bits that
+ * were returned by sdio_get_host_pm_caps().
+ * The host doesn't need to be claimed, nor the function active,
+ * for this information to be set.
+ */
+int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
+{
+ struct mmc_host *host;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ host = func->card->host;
+
+ if (flags & ~host->pm_caps)
+ return -EINVAL;
+
+ /* function suspend methods are serialized, hence no lock needed */
+ host->pm_flags |= flags;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index eaf3636..43eaf5c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/mmc/core.h>
+#include <linux/mmc/pm.h>
struct mmc_ios {
unsigned int clock; /* clock rate */
@@ -152,6 +153,8 @@ struct mmc_host {
#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
+ mmc_pm_flag_t pm_caps; /* supported pm features */
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
@@ -197,6 +200,8 @@ struct mmc_host {
struct task_struct *sdio_irq_thread;
atomic_t sdio_irq_thread_abort;
+ mmc_pm_flag_t pm_flags; /* requested pm features */
+
#ifdef CONFIG_LEDS_TRIGGERS
struct led_trigger *led; /* activity led */
#endif
diff --git a/include/linux/mmc/pm.h b/include/linux/mmc/pm.h
new file mode 100644
index 0000000..d37aac4
--- /dev/null
+++ b/include/linux/mmc/pm.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/linux/mmc/pm.h
+ *
+ * Author: Nicolas Pitre
+ * Copyright: (C) 2009 Marvell Technology Group Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LINUX_MMC_PM_H
+#define LINUX_MMC_PM_H
+
+/*
+ * These flags are used to describe power management features that
+ * some cards (typically SDIO cards) might wish to benefit from when
+ * the host system is being suspended. There are several layers of
+ * abstractions involved, from the host controller driver, to the MMC core
+ * code, to the SDIO core code, to finally get to the actual SDIO function
+ * driver. This file is therefore used for common definitions shared across
+ * all those layers.
+ */
+
+typedef unsigned int mmc_pm_flag_t;
+
+#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */
+#define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */
+
+#endif
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index ac3ab68..c6c0cce 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
+#include <linux/mmc/pm.h>
+
struct mmc_card;
struct sdio_func;
@@ -153,5 +155,8 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func,
extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
unsigned int addr, int *err_ret);
+extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func);
+extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags);
+
#endif
--
1.7.0.rc2.1.g694b5
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 1/5] SDIO: introduce API for special power management features
2010-02-09 20:29 ` [PATCH 1/5] SDIO: introduce API for special power management features Nicolas Pitre
@ 2010-02-11 20:32 ` Andrew Morton
2010-02-11 20:57 ` Nicolas Pitre
0 siblings, 1 reply; 13+ messages in thread
From: Andrew Morton @ 2010-02-11 20:32 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: linux-mmc
On Tue, 09 Feb 2010 15:29:22 -0500
Nicolas Pitre <nico@fluxnic.net> wrote:
> + BUG_ON(!func);
> + BUG_ON(!func->card);
> +
> + host = func->card->host;
It's a bit redundant to check for null and then deref the pointer - the
kernel will reliably oops on the NULL deref, which gives us the same
info.
I guess the BUG_ON is more useful in the case where a double-deref is
being performed, as it can otherwise be a bit hard to work out which
pointer was NULL.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/5] SDIO: introduce API for special power management features
2010-02-11 20:32 ` Andrew Morton
@ 2010-02-11 20:57 ` Nicolas Pitre
0 siblings, 0 replies; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-11 20:57 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
On Thu, 11 Feb 2010, Andrew Morton wrote:
> On Tue, 09 Feb 2010 15:29:22 -0500
> Nicolas Pitre <nico@fluxnic.net> wrote:
>
> > + BUG_ON(!func);
> > + BUG_ON(!func->card);
> > +
> > + host = func->card->host;
>
> It's a bit redundant to check for null and then deref the pointer - the
> kernel will reliably oops on the NULL deref, which gives us the same
> info.
>
> I guess the BUG_ON is more useful in the case where a double-deref is
> being performed, as it can otherwise be a bit hard to work out which
> pointer was NULL.
The actual reason for those is to follow the same pattern as found in
surrounding functions. I personally think there are a bit too many of
those but Pierre Ossman liked them.
Nicolas
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 2/5] SDIO: sdhci support for suspend mode PM features
2010-02-09 20:29 [PATCH 0/5] SDIO support for "powered" suspend Nicolas Pitre
2010-02-09 20:29 ` [PATCH 1/5] SDIO: introduce API for special power management features Nicolas Pitre
@ 2010-02-09 20:29 ` Nicolas Pitre
2010-02-09 20:29 ` [PATCH 3/5] SDIO: Don't use CMD[357] as part of a powered SDIO resume Nicolas Pitre
` (2 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-09 20:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
Tested with an XO v1.5 from OLPC.
Signed-off-by: Nicolas Pitre <nico@marvell.com>
---
drivers/mmc/host/sdhci-pci.c | 17 ++++++++++++++---
drivers/mmc/host/sdhci.c | 26 +++++++++++++++++---------
2 files changed, 31 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 5c3a176..dbf0543 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -501,6 +501,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ mmc_pm_flag_t pm_flags = 0;
int i, ret;
chip = pci_get_drvdata(pdev);
@@ -519,6 +520,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
sdhci_resume_host(chip->slots[i]->host);
return ret;
}
+
+ pm_flags |= slot->host->mmc->pm_flags;
}
if (chip->fixes && chip->fixes->suspend) {
@@ -531,9 +534,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
}
pci_save_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (pm_flags & MMC_PM_KEEP_POWER) {
+ if (pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ }
return 0;
}
@@ -653,6 +662,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
goto unmap;
}
+ host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
+
ret = sdhci_add_host(host);
if (ret)
goto remove;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c279fbc..5b3efc4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -174,20 +174,31 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
}
-static void sdhci_init(struct sdhci_host *host)
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+
+static void sdhci_init(struct sdhci_host *host, int soft)
{
- sdhci_reset(host, SDHCI_RESET_ALL);
+ if (soft)
+ sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+ else
+ sdhci_reset(host, SDHCI_RESET_ALL);
sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+
+ if (soft) {
+ /* force clock reconfiguration */
+ host->clock = 0;
+ sdhci_set_ios(host->mmc, &host->mmc->ios);
+ }
}
static void sdhci_reinit(struct sdhci_host *host)
{
- sdhci_init(host);
+ sdhci_init(host, 0);
sdhci_enable_card_detection(host);
}
@@ -1610,16 +1621,13 @@ int sdhci_resume_host(struct sdhci_host *host)
if (ret)
return ret;
- sdhci_init(host);
+ sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
mmiowb();
ret = mmc_resume_host(host->mmc);
- if (ret)
- return ret;
-
sdhci_enable_card_detection(host);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(sdhci_resume_host);
@@ -1874,7 +1882,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret)
goto untasklet;
- sdhci_init(host);
+ sdhci_init(host, 0);
#ifdef CONFIG_MMC_DEBUG
sdhci_dumpregs(host);
--
1.7.0.rc2.1.g694b5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 3/5] SDIO: Don't use CMD[357] as part of a powered SDIO resume
2010-02-09 20:29 [PATCH 0/5] SDIO support for "powered" suspend Nicolas Pitre
2010-02-09 20:29 ` [PATCH 1/5] SDIO: introduce API for special power management features Nicolas Pitre
2010-02-09 20:29 ` [PATCH 2/5] SDIO: sdhci support for suspend mode PM features Nicolas Pitre
@ 2010-02-09 20:29 ` Nicolas Pitre
2010-02-09 20:29 ` [PATCH 4/5] SDIO: kick the interrupt thread upon a resume Nicolas Pitre
2010-02-09 20:29 ` [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend Nicolas Pitre
4 siblings, 0 replies; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-09 20:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
From: Chris Ball <cjb@laptop.org>
Seen on a Marvell 8686 SDIO card and Via VX855 controller: we must avoid
sending CMD3/5/7 on a resume where power has been maintained, because the
8686 will refuse to respond to them and the MMC stack will give up on
the card.
Signed-off-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Nicolas Pitre <nico@marvell.com>
---
drivers/mmc/core/sdio.c | 19 +++++++++++--------
1 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 06b6408..7d8ba64 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -224,7 +224,7 @@ static int sdio_enable_hs(struct mmc_card *card)
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard)
+ struct mmc_card *oldcard, int powered_resume)
{
struct mmc_card *card;
int err;
@@ -235,9 +235,11 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* Inform the card of the voltage
*/
- err = mmc_send_io_op_cond(host, host->ocr, &ocr);
- if (err)
- goto err;
+ if (!powered_resume) {
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+ }
/*
* For SPI, enable CRC as appropriate.
@@ -262,7 +264,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* For native busses: set card RCA and quit open drain mode.
*/
- if (!mmc_host_is_spi(host)) {
+ if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
@@ -273,7 +275,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* Select card, as all following commands rely on that.
*/
- if (!mmc_host_is_spi(host)) {
+ if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
@@ -437,7 +439,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
- err = mmc_sdio_init_card(host, host->ocr, host->card);
+ err = mmc_sdio_init_card(host, host->ocr, host->card,
+ (host->pm_flags & MMC_PM_KEEP_POWER));
mmc_release_host(host);
/*
@@ -507,7 +510,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
/*
* Detect and init the card.
*/
- err = mmc_sdio_init_card(host, host->ocr, NULL);
+ err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err)
goto err;
card = host->card;
--
1.7.0.rc2.1.g694b5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 4/5] SDIO: kick the interrupt thread upon a resume
2010-02-09 20:29 [PATCH 0/5] SDIO support for "powered" suspend Nicolas Pitre
` (2 preceding siblings ...)
2010-02-09 20:29 ` [PATCH 3/5] SDIO: Don't use CMD[357] as part of a powered SDIO resume Nicolas Pitre
@ 2010-02-09 20:29 ` Nicolas Pitre
2010-02-09 20:29 ` [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend Nicolas Pitre
4 siblings, 0 replies; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-09 20:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
Some SDIO cards may suspend while keeping function interrupts active
especially in the powered suspend case. Upon resume we need to kick
the SDIO interrupt thread to check for pending interrupts and to restart
card IRQ detection at the host controller level.
Signed-off-by: Nicolas Pitre <nico@marvell.com>
---
drivers/mmc/core/sdio.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 7d8ba64..5840de1 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -441,6 +441,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
mmc_claim_host(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
(host->pm_flags & MMC_PM_KEEP_POWER));
+ if (!err && host->sdio_irqs)
+ mmc_signal_sdio_irq(host);
mmc_release_host(host);
/*
--
1.7.0.rc2.1.g694b5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-09 20:29 [PATCH 0/5] SDIO support for "powered" suspend Nicolas Pitre
` (3 preceding siblings ...)
2010-02-09 20:29 ` [PATCH 4/5] SDIO: kick the interrupt thread upon a resume Nicolas Pitre
@ 2010-02-09 20:29 ` Nicolas Pitre
2010-02-10 11:30 ` David Vrabel
4 siblings, 1 reply; 13+ messages in thread
From: Nicolas Pitre @ 2010-02-09 20:29 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-mmc
From: Daniel Drake <dsd@laptop.org>
And bring them back to 4-bit mode during resume.
Signed-off-by: Daniel Drake <dsd@laptop.org>
Signed-off-by: Nicolas Pitre <nico@marvell.com>
---
drivers/mmc/core/sdio.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mmc/sdio.h | 2 ++
2 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 5840de1..2dd4cfe 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -188,6 +188,40 @@ static int sdio_disable_cd(struct mmc_card *card)
}
/*
+ * Devices that remain active during a system suspend are
+ * put back into 1-bit mode.
+ */
+static int sdio_disable_wide(struct mmc_card *card)
+{
+ int ret;
+ u8 ctrl;
+
+ if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+ return 0;
+
+ if (card->cccr.low_speed && !card->cccr.wide_bus)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+ if (ret)
+ return ret;
+
+ if (!(ctrl & SDIO_BUS_WIDTH_4BIT))
+ return 0;
+
+ ctrl &= ~SDIO_BUS_WIDTH_4BIT;
+ ctrl |= SDIO_BUS_ASYNC_INT;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+ if (ret)
+ return ret;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_1);
+
+ return 0;
+}
+
+/*
* Test if the card supports high-speed mode and, if so, switch to it.
*/
static int sdio_enable_hs(struct mmc_card *card)
@@ -427,6 +461,12 @@ static int mmc_sdio_suspend(struct mmc_host *host)
}
}
+ if (!err && host->pm_flags & MMC_PM_KEEP_POWER) {
+ mmc_claim_host(host);
+ sdio_disable_wide(host->card);
+ mmc_release_host(host);
+ }
+
return err;
}
@@ -441,6 +481,9 @@ static int mmc_sdio_resume(struct mmc_host *host)
mmc_claim_host(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
(host->pm_flags & MMC_PM_KEEP_POWER));
+ if (!err)
+ /* We may have switched to 1-bit mode during suspend. */
+ err = sdio_enable_wide(host->card);
if (!err && host->sdio_irqs)
mmc_signal_sdio_irq(host);
mmc_release_host(host);
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 47ba464..0ebaef5 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -95,6 +95,8 @@
#define SDIO_BUS_WIDTH_1BIT 0x00
#define SDIO_BUS_WIDTH_4BIT 0x02
+#define SDIO_BUS_ASYNC_INT 0x20
+
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
#define SDIO_CCCR_CAPS 0x08
--
1.7.0.rc2.1.g694b5
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-09 20:29 ` [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend Nicolas Pitre
@ 2010-02-10 11:30 ` David Vrabel
2010-02-10 15:17 ` Chris Ball
0 siblings, 1 reply; 13+ messages in thread
From: David Vrabel @ 2010-02-10 11:30 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Andrew Morton, linux-mmc
Nicolas Pitre wrote:
> From: Daniel Drake <dsd@laptop.org>
>
> And bring them back to 4-bit mode during resume.
Why? Is this for a specific card that doesn't support asynchronous card
interrupts while in 4-bit mode? If so, I'd suggest a card quirk for
this and only switch modes for these cards.
> + ctrl |= SDIO_BUS_ASYNC_INT;
This bit is for SPI mode only. Why are you setting it here?
David
--
David Vrabel, Senior Software Engineer, Drivers
CSR, Churchill House, Cambridge Business Park, Tel: +44 (0)1223 692562
Cowley Road, Cambridge, CB4 0WZ http://www.csr.com/
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-10 11:30 ` David Vrabel
@ 2010-02-10 15:17 ` Chris Ball
2010-02-10 16:03 ` David Vrabel
0 siblings, 1 reply; 13+ messages in thread
From: Chris Ball @ 2010-02-10 15:17 UTC (permalink / raw)
To: David Vrabel; +Cc: Nicolas Pitre, Andrew Morton, linux-mmc
Hi David,
> Why? Is this for a specific card that doesn't support
> asynchronous card interrupts while in 4-bit mode? If so, I'd
> suggest a card quirk for this and only switch modes for these
> cards.
(As a check that we're on the same page -- sdio_disable_wide() is only
called if MMC_PM_KEEP_POWER is true, which means the system is going
to be suspended but the card will remain externally powered without
its clock.)
Under the circumstances above, it's a requirement of the SDIO spec
that moving to 1-bit mode must happen before stopping the clock if
the interrupt mechanism is to be used to wake the host, and the
chipset we've been using (Via VX855) fails to generate a wakeup if
the switch isn't made. Do you have experience of another chipset
that doesn't need the switch to 1-bit mode for a clockless wakeup?
Thanks,
- Chris.
--
Chris Ball <cjb@laptop.org>
One Laptop Per Child
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-10 15:17 ` Chris Ball
@ 2010-02-10 16:03 ` David Vrabel
2010-02-10 16:32 ` Chris Ball
0 siblings, 1 reply; 13+ messages in thread
From: David Vrabel @ 2010-02-10 16:03 UTC (permalink / raw)
To: Chris Ball; +Cc: Nicolas Pitre, Andrew Morton, linux-mmc
Chris Ball wrote:
> Hi David,
>
> > Why? Is this for a specific card that doesn't support
> > asynchronous card interrupts while in 4-bit mode? If so, I'd
> > suggest a card quirk for this and only switch modes for these
> > cards.
>
> (As a check that we're on the same page -- sdio_disable_wide() is only
> called if MMC_PM_KEEP_POWER is true, which means the system is going
> to be suspended but the card will remain externally powered without
> its clock.)
>
> Under the circumstances above, it's a requirement of the SDIO spec
> that moving to 1-bit mode must happen before stopping the clock if
> the interrupt mechanism is to be used to wake the host, and the
> chipset we've been using (Via VX855) fails to generate a wakeup if
> the switch isn't made. Do you have experience of another chipset
> that doesn't need the switch to 1-bit mode for a clockless wakeup?
I couldn't find anything in the SDIO specification (you know the section
number?). Part A2 has a requirement that the controller be placed into
1-bit mode but this doesn't mean that the card has to be.
Maybe it's not really a big deal, a single command only costs a few 10s
of microseconds anyway.
David
--
David Vrabel, Senior Software Engineer, Drivers
CSR, Churchill House, Cambridge Business Park, Tel: +44 (0)1223 692562
Cowley Road, Cambridge, CB4 0WZ http://www.csr.com/
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-10 16:03 ` David Vrabel
@ 2010-02-10 16:32 ` Chris Ball
2010-02-10 16:49 ` David Vrabel
0 siblings, 1 reply; 13+ messages in thread
From: Chris Ball @ 2010-02-10 16:32 UTC (permalink / raw)
To: David Vrabel; +Cc: Nicolas Pitre, Andrew Morton, linux-mmc
Hi David,
> I couldn't find anything in the SDIO specification (you know the
> section number?). Part A2 has a requirement that the controller
> be placed into 1-bit mode but this doesn't mean that the card has
> to be.
I think it's part E1 section 8, and does specify that it's necessary
for both host and card.
> Maybe it's not really a big deal, a single command only costs a
> few 10s of microseconds anyway.
Yeah, and it's only being sent on a powered-suspend, which so far OLPC
is the only user of -- I'd rather have the next user tell us it isn't
necessary than break it for them by introducing an incorrect quirk.
Thanks,
- Chris.
--
Chris Ball <cjb@laptop.org>
One Laptop Per Child
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 5/5] SDIO: put active devices into 1-bit mode during suspend
2010-02-10 16:32 ` Chris Ball
@ 2010-02-10 16:49 ` David Vrabel
0 siblings, 0 replies; 13+ messages in thread
From: David Vrabel @ 2010-02-10 16:49 UTC (permalink / raw)
To: Chris Ball; +Cc: Nicolas Pitre, Andrew Morton, linux-mmc
Chris Ball wrote:
> Hi David,
>
> > I couldn't find anything in the SDIO specification (you know the
> > section number?). Part A2 has a requirement that the controller
> > be placed into 1-bit mode but this doesn't mean that the card has
> > to be.
>
> I think it's part E1 section 8, and does specify that it's necessary
> for both host and card.
Found it now, thanks. The patch is fine as is.
(FWIW, my confusion arose because CSR chips can assert interrupts in
4-bit mode even without SDCLK.)
David
--
David Vrabel, Senior Software Engineer, Drivers
CSR, Churchill House, Cambridge Business Park, Tel: +44 (0)1223 692562
Cowley Road, Cambridge, CB4 0WZ http://www.csr.com/
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
^ permalink raw reply [flat|nested] 13+ messages in thread