From 20758b66dce76af0527363186f44b464d83e5666 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:12 +0300 Subject: mmc: sdhci: add eMMC hardware reset support Add an SDHCI operation for hardware reset and connect it to the host controller operation. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0e02cc1df12e..d66a7a11a4fc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1471,6 +1471,14 @@ static int sdhci_get_ro(struct mmc_host *mmc) return 0; } +static void sdhci_hw_reset(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (host->ops && host->ops->hw_reset) + host->ops->hw_reset(host); +} + static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host; @@ -1805,6 +1813,7 @@ static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, -- cgit From 88b47679746b81534002bcba42da97ab82b5d12a Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 3 Jul 2011 15:15:51 -0400 Subject: mmc: Add module.h to drivers/mmc users assuming implicit presence. We are cleaning up the implicit presence of module.h; these guys are some of the people who just assume it will be there. Call it out explitly for those that really need it. Signed-off-by: Paul Gortmaker Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d66a7a11a4fc..9394860602fe 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include -- cgit From 66fd8ad5100b5003046aa744a4f12fa31bb831f9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 3 Oct 2011 15:33:34 +0300 Subject: mmc: sdhci-pci: add runtime pm support Ths patch allows runtime PM for sdhci-pci, runtime suspending after inactivity of 50ms and ensuring runtime resume before SDHC registers are accessed. During runtime suspend, interrupts are masked. The host controller state is restored at runtime resume. For Medfield, the host controller's card detect mechanism is supplanted by an always-on GPIO which provides for card detect wake-up. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 255 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 211 insertions(+), 44 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9394860602fe..155deb8629af 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -42,6 +43,7 @@ #define MAX_TUNING_LOOP 40 static unsigned int debug_quirks = 0; +static unsigned int debug_quirks2; static void sdhci_finish_data(struct sdhci_host *); @@ -50,6 +52,20 @@ static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc); static void sdhci_tuning_timer(unsigned long data); +#ifdef CONFIG_PM_RUNTIME +static int sdhci_runtime_pm_get(struct sdhci_host *host); +static int sdhci_runtime_pm_put(struct sdhci_host *host); +#else +static inline int sdhci_runtime_pm_get(struct sdhci_host *host) +{ + return 0; +} +static inline int sdhci_runtime_pm_put(struct sdhci_host *host) +{ + return 0; +} +#endif + static void sdhci_dumpregs(struct sdhci_host *host) { printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", @@ -133,6 +149,9 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) return; + if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) + return; + present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; @@ -252,11 +271,14 @@ static void sdhci_led_control(struct led_classdev *led, spin_lock_irqsave(&host->lock, flags); + if (host->runtime_suspended) + goto out; + if (brightness == LED_OFF) sdhci_deactivate_led(host); else sdhci_activate_led(host); - +out: spin_unlock_irqrestore(&host->lock, flags); } #endif @@ -1210,6 +1232,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host = mmc_priv(mmc); + sdhci_runtime_pm_get(host); + spin_lock_irqsave(&host->lock, flags); WARN_ON(host->mrq != NULL); @@ -1270,14 +1294,11 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) { - struct sdhci_host *host; unsigned long flags; u8 ctrl; - host = mmc_priv(mmc); - spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) @@ -1427,7 +1448,16 @@ out: spin_unlock_irqrestore(&host->lock, flags); } -static int check_ro(struct sdhci_host *host) +static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_runtime_pm_get(host); + sdhci_do_set_ios(host, ios); + sdhci_runtime_pm_put(host); +} + +static int sdhci_check_ro(struct sdhci_host *host) { unsigned long flags; int is_readonly; @@ -1451,19 +1481,16 @@ static int check_ro(struct sdhci_host *host) #define SAMPLE_COUNT 5 -static int sdhci_get_ro(struct mmc_host *mmc) +static int sdhci_do_get_ro(struct sdhci_host *host) { - struct sdhci_host *host; int i, ro_count; - host = mmc_priv(mmc); - if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) - return check_ro(host); + return sdhci_check_ro(host); ro_count = 0; for (i = 0; i < SAMPLE_COUNT; i++) { - if (check_ro(host)) { + if (sdhci_check_ro(host)) { if (++ro_count > SAMPLE_COUNT / 2) return 1; } @@ -1480,38 +1507,56 @@ static void sdhci_hw_reset(struct mmc_host *mmc) host->ops->hw_reset(host); } -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +static int sdhci_get_ro(struct mmc_host *mmc) { - struct sdhci_host *host; - unsigned long flags; - - host = mmc_priv(mmc); + struct sdhci_host *host = mmc_priv(mmc); + int ret; - spin_lock_irqsave(&host->lock, flags); + sdhci_runtime_pm_get(host); + ret = sdhci_do_get_ro(host); + sdhci_runtime_pm_put(host); + return ret; +} +static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) +{ if (host->flags & SDHCI_DEVICE_DEAD) goto out; + if (enable) + host->flags |= SDHCI_SDIO_IRQ_ENABLED; + else + host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; + + /* SDIO IRQ will be enabled as appropriate in runtime resume */ + if (host->runtime_suspended) + goto out; + if (enable) sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); else sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); out: mmiowb(); +} + +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + spin_lock_irqsave(&host->lock, flags); + sdhci_enable_sdio_irq_nolock(host, enable); spin_unlock_irqrestore(&host->lock, flags); } -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) +static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, + struct mmc_ios *ios) { - struct sdhci_host *host; u8 pwr; u16 clk, ctrl; u32 present_state; - host = mmc_priv(mmc); - /* * Signal Voltage Switching is only applicable for Host Controllers * v3.00 and above. @@ -1604,6 +1649,20 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + int err; + + if (host->version < SDHCI_SPEC_300) + return 0; + sdhci_runtime_pm_get(host); + err = sdhci_do_start_signal_voltage_switch(host, ios); + sdhci_runtime_pm_put(host); + return err; +} + static int sdhci_execute_tuning(struct mmc_host *mmc) { struct sdhci_host *host; @@ -1615,6 +1674,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) host = mmc_priv(mmc); + sdhci_runtime_pm_get(host); disable_irq(host->irq); spin_lock(&host->lock); @@ -1632,6 +1692,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) else { spin_unlock(&host->lock); enable_irq(host->irq); + sdhci_runtime_pm_put(host); return 0; } @@ -1657,7 +1718,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) timeout = 150; do { struct mmc_command cmd = {0}; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; if (!tuning_loop_counter && !timeout) break; @@ -1775,18 +1836,16 @@ out: sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); spin_unlock(&host->lock); enable_irq(host->irq); + sdhci_runtime_pm_put(host); return err; } -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) +static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) { - struct sdhci_host *host; u16 ctrl; unsigned long flags; - host = mmc_priv(mmc); - /* Host Controller v3.00 defines preset value registers */ if (host->version < SDHCI_SPEC_300) return; @@ -1802,14 +1861,25 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + host->flags |= SDHCI_PV_ENABLED; } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + host->flags &= ~SDHCI_PV_ENABLED; } spin_unlock_irqrestore(&host->lock, flags); } +static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_runtime_pm_get(host); + sdhci_do_enable_preset_value(host, enable); + sdhci_runtime_pm_put(host); +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, @@ -1836,19 +1906,19 @@ static void sdhci_tasklet_card(unsigned long param) spin_lock_irqsave(&host->lock, flags); - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - if (host->mrq) { - printk(KERN_ERR "%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Resetting controller.\n", - mmc_hostname(host->mmc)); + /* Check host->mrq first in case we are runtime suspended */ + if (host->mrq && + !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + printk(KERN_ERR "%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Resetting controller.\n", + mmc_hostname(host->mmc)); - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); } spin_unlock_irqrestore(&host->lock, flags); @@ -1864,14 +1934,16 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + spin_lock_irqsave(&host->lock, flags); + /* * If this tasklet gets rescheduled while running, it will * be run again afterwards but without any active request. */ - if (!host->mrq) + if (!host->mrq) { + spin_unlock_irqrestore(&host->lock, flags); return; - - spin_lock_irqsave(&host->lock, flags); + } del_timer(&host->timer); @@ -1915,6 +1987,7 @@ static void sdhci_tasklet_finish(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); + sdhci_runtime_pm_put(host); } static void sdhci_timeout_timer(unsigned long data) @@ -2146,12 +2219,19 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; - struct sdhci_host* host = dev_id; + struct sdhci_host *host = dev_id; u32 intmask; int cardint = 0; spin_lock(&host->lock); + if (host->runtime_suspended) { + spin_unlock(&host->lock); + printk(KERN_WARNING "%s: got irq while runtime suspended\n", + mmc_hostname(host->mmc)); + return IRQ_HANDLED; + } + intmask = sdhci_readl(host, SDHCI_INT_STATUS); if (!intmask || intmask == 0xffffffff) { @@ -2285,7 +2365,6 @@ int sdhci_resume_host(struct sdhci_host *host) return ret; } - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); @@ -2324,6 +2403,90 @@ EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_runtime_pm_get(struct sdhci_host *host) +{ + return pm_runtime_get_sync(host->mmc->parent); +} + +static int sdhci_runtime_pm_put(struct sdhci_host *host) +{ + pm_runtime_mark_last_busy(host->mmc->parent); + return pm_runtime_put_autosuspend(host->mmc->parent); +} + +int sdhci_runtime_suspend_host(struct sdhci_host *host) +{ + unsigned long flags; + int ret = 0; + + /* Disable tuning since we are suspending */ + if (host->version >= SDHCI_SPEC_300 && + host->tuning_mode == SDHCI_TUNING_MODE_1) { + del_timer_sync(&host->tuning_timer); + host->flags &= ~SDHCI_NEEDS_RETUNING; + } + + spin_lock_irqsave(&host->lock, flags); + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); + spin_unlock_irqrestore(&host->lock, flags); + + synchronize_irq(host->irq); + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); + +int sdhci_runtime_resume_host(struct sdhci_host *host) +{ + unsigned long flags; + int ret = 0, host_flags = host->flags; + + if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { + if (host->ops->enable_dma) + host->ops->enable_dma(host); + } + + sdhci_init(host, 0); + + /* Force clock and power re-program */ + host->pwr = 0; + host->clock = 0; + sdhci_do_set_ios(host, &host->mmc->ios); + + sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); + if (host_flags & SDHCI_PV_ENABLED) + sdhci_do_enable_preset_value(host, true); + + /* Set the re-tuning expiration flag */ + if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && + (host->tuning_mode == SDHCI_TUNING_MODE_1)) + host->flags |= SDHCI_NEEDS_RETUNING; + + spin_lock_irqsave(&host->lock, flags); + + host->runtime_suspended = false; + + /* Enable SDIO IRQ */ + if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) + sdhci_enable_sdio_irq_nolock(host, true); + + /* Enable Card Detection */ + sdhci_enable_card_detection(host); + + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); + +#endif + /*****************************************************************************\ * * * Device allocation/registration * @@ -2366,6 +2529,8 @@ int sdhci_add_host(struct sdhci_host *host) if (debug_quirks) host->quirks = debug_quirks; + if (debug_quirks2) + host->quirks2 = debug_quirks2; sdhci_reset(host, SDHCI_RESET_ALL); @@ -2888,9 +3053,11 @@ module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); module_param(debug_quirks, uint, 0444); +module_param(debug_quirks2, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); +MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); -- cgit From a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Tue, 11 Oct 2011 11:44:09 +0530 Subject: mmc: replace printk with appropriate display macro All the files using printk function for displaying kernel messages in the mmc driver have been replaced with corresponding macro. Signed-off-by: Girish K S Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 92 +++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 47 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 155deb8629af..2cc3ffa7d766 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -68,51 +68,51 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host) static void sdhci_dumpregs(struct sdhci_host *host) { - printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", + pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); - printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", sdhci_readl(host, SDHCI_DMA_ADDRESS), sdhci_readw(host, SDHCI_HOST_VERSION)); - printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", sdhci_readw(host, SDHCI_BLOCK_SIZE), sdhci_readw(host, SDHCI_BLOCK_COUNT)); - printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", sdhci_readl(host, SDHCI_ARGUMENT), sdhci_readw(host, SDHCI_TRANSFER_MODE)); - printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", sdhci_readl(host, SDHCI_PRESENT_STATE), sdhci_readb(host, SDHCI_HOST_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", sdhci_readb(host, SDHCI_POWER_CONTROL), sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), sdhci_readl(host, SDHCI_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE), sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", sdhci_readw(host, SDHCI_ACMD12_ERR), sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", + pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_CAPABILITIES_1)); - printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", + pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", sdhci_readw(host, SDHCI_COMMAND), sdhci_readl(host, SDHCI_MAX_CURRENT)); - printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n", + pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", sdhci_readw(host, SDHCI_HOST_CONTROL2)); if (host->flags & SDHCI_USE_ADMA) - printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", readl(host->ioaddr + SDHCI_ADMA_ERROR), readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); - printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); + pr_debug(DRIVER_NAME ": ===========================================\n"); } /*****************************************************************************\ @@ -200,7 +200,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) /* hw clears the bit when it's done */ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printk(KERN_ERR "%s: Reset 0x%x never completed.\n", + pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); sdhci_dumpregs(host); return; @@ -677,7 +677,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n", + pr_warning("%s: Too large timeout requested for CMD%d!\n", mmc_hostname(host->mmc), cmd->opcode); count = 0xE; } @@ -972,7 +972,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { - printk(KERN_ERR "%s: Controller never released " + pr_err("%s: Controller never released " "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = -EIO; @@ -994,7 +994,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_set_transfer_mode(host, cmd); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - printk(KERN_ERR "%s: Unsupported response type!\n", + pr_err("%s: Unsupported response type!\n", mmc_hostname(host->mmc)); cmd->error = -EINVAL; tasklet_schedule(&host->finish_tasklet); @@ -1144,7 +1144,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printk(KERN_ERR "%s: Internal clock never " + pr_err("%s: Internal clock never " "stabilised.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; @@ -1582,7 +1582,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, if (!(ctrl & SDHCI_CTRL_VDD_180)) return 0; else { - printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V " + pr_info(DRIVER_NAME ": Switching to 3.3V " "signalling voltage failed\n"); return -EIO; } @@ -1641,7 +1641,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling " + pr_info(DRIVER_NAME ": Switching to 1.8V signalling " "voltage failed, retrying with S18R set to 0\n"); return -EAGAIN; } else @@ -1764,7 +1764,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) spin_lock(&host->lock); if (!host->tuning_done) { - printk(KERN_INFO DRIVER_NAME ": Timeout waiting for " + pr_info(DRIVER_NAME ": Timeout waiting for " "Buffer Read Ready interrupt during tuning " "procedure, falling back to fixed sampling " "clock\n"); @@ -1794,7 +1794,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); } else { if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - printk(KERN_INFO DRIVER_NAME ": Tuning procedure" + pr_info(DRIVER_NAME ": Tuning procedure" " failed, falling back to fixed sampling" " clock\n"); err = -EIO; @@ -1909,9 +1909,9 @@ static void sdhci_tasklet_card(unsigned long param) /* Check host->mrq first in case we are runtime suspended */ if (host->mrq && !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - printk(KERN_ERR "%s: Card removed during transfer!\n", + pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Resetting controller.\n", + pr_err("%s: Resetting controller.\n", mmc_hostname(host->mmc)); sdhci_reset(host, SDHCI_RESET_CMD); @@ -2000,7 +2000,7 @@ static void sdhci_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); if (host->mrq) { - printk(KERN_ERR "%s: Timeout waiting for hardware " + pr_err("%s: Timeout waiting for hardware " "interrupt.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); @@ -2046,7 +2046,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { - printk(KERN_ERR "%s: Got command interrupt 0x%08x even " + pr_err("%s: Got command interrupt 0x%08x even " "though no command operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2146,7 +2146,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } - printk(KERN_ERR "%s: Got data interrupt 0x%08x even " + pr_err("%s: Got data interrupt 0x%08x even " "though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2163,7 +2163,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) != MMC_BUS_TEST_R) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { - printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); + pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; } @@ -2227,7 +2227,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (host->runtime_suspended) { spin_unlock(&host->lock); - printk(KERN_WARNING "%s: got irq while runtime suspended\n", + pr_warning("%s: got irq while runtime suspended\n", mmc_hostname(host->mmc)); return IRQ_HANDLED; } @@ -2284,7 +2284,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_ERROR; if (intmask & SDHCI_INT_BUS_POWER) { - printk(KERN_ERR "%s: Card is consuming too much power!\n", + pr_err("%s: Card is consuming too much power!\n", mmc_hostname(host->mmc)); sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); } @@ -2297,7 +2297,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_CARD_INT; if (intmask) { - printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", + pr_err("%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); sdhci_dumpregs(host); @@ -2538,7 +2538,7 @@ int sdhci_add_host(struct sdhci_host *host) host->version = (host->version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (host->version > SDHCI_SPEC_300) { - printk(KERN_ERR "%s: Unknown controller version (%d). " + pr_err("%s: Unknown controller version (%d). " "You may experience problems.\n", mmc_hostname(mmc), host->version); } @@ -2575,7 +2575,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { - printk(KERN_WARNING "%s: No suitable DMA " + pr_warning("%s: No suitable DMA " "available. Falling back to PIO.\n", mmc_hostname(mmc)); host->flags &= @@ -2595,7 +2595,7 @@ int sdhci_add_host(struct sdhci_host *host) if (!host->adma_desc || !host->align_buffer) { kfree(host->adma_desc); kfree(host->align_buffer); - printk(KERN_WARNING "%s: Unable to allocate ADMA " + pr_warning("%s: Unable to allocate ADMA " "buffers. Falling back to standard DMA.\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; @@ -2623,8 +2623,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { if (!host->ops->get_max_clock) { - printk(KERN_ERR - "%s: Hardware doesn't specify base clock " + pr_err("%s: Hardware doesn't specify base clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2670,8 +2669,7 @@ int sdhci_add_host(struct sdhci_host *host) host->timeout_clk = host->ops->get_timeout_clock(host); } else if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - printk(KERN_ERR - "%s: Hardware doesn't specify timeout clock " + pr_err("%s: Hardware doesn't specify timeout clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2830,7 +2828,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ocr_avail_mmc &= host->ocr_avail_mmc; if (mmc->ocr_avail == 0) { - printk(KERN_ERR "%s: Hardware doesn't report any " + pr_err("%s: Hardware doesn't report any " "support voltages.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2878,7 +2876,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { - printk(KERN_WARNING "%s: Invalid maximum block size, " + pr_warning("%s: Invalid maximum block size, " "assuming 512 bytes\n", mmc_hostname(mmc)); mmc->max_blk_size = 0; } @@ -2917,7 +2915,7 @@ int sdhci_add_host(struct sdhci_host *host) host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { - printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; } else { regulator_enable(host->vmmc); @@ -2946,7 +2944,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc_add_host(mmc); - printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n", + pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), (host->flags & SDHCI_USE_ADMA) ? "ADMA" : (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); @@ -2979,7 +2977,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) host->flags |= SDHCI_DEVICE_DEAD; if (host->mrq) { - printk(KERN_ERR "%s: Controller removed during " + pr_err("%s: Controller removed during " " transfer!\n", mmc_hostname(host->mmc)); host->mrq->cmd->error = -ENOMEDIUM; @@ -3038,9 +3036,9 @@ EXPORT_SYMBOL_GPL(sdhci_free_host); static int __init sdhci_drv_init(void) { - printk(KERN_INFO DRIVER_NAME + pr_info(DRIVER_NAME ": Secure Digital Host Controller Interface driver\n"); - printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); return 0; } -- cgit From bec8726abc72bf30d2743a722aa37cd69e7a0580 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Thu, 13 Oct 2011 12:04:16 +0530 Subject: mmc: core: Add Power Off Notify Feature eMMC 4.5 This patch adds support for the power off notify feature, available in eMMC 4.5 devices. If the host has support for this feature, then the mmc core will notify the device by setting the POWER_OFF_NOTIFICATION byte in the extended csd register with a value of 1 (POWER_ON). For suspend mode short timeout is used, whereas for the normal poweroff long timeout is used. Signed-off-by: Girish K S Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2cc3ffa7d766..6d8eea323541 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2739,6 +2739,15 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_DRIVER_TYPE_D) mmc->caps |= MMC_CAP_DRIVER_TYPE_D; + /* + * If Power Off Notify capability is enabled by the host, + * set notify to short power off notify timeout value. + */ + if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY) + mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; + else + mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE; + /* Initial value for re-tuning timer count */ host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> SDHCI_RETUNING_TIMER_COUNT_SHIFT; -- cgit