From patchwork Fri Mar 30 09:14:17 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saugata Das X-Patchwork-Id: 7529 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 220F823E2F for ; Fri, 30 Mar 2012 09:14:53 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id B47D1A18068 for ; Fri, 30 Mar 2012 09:14:52 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id e36so1013782iag.11 for ; Fri, 30 Mar 2012 02:14:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:mime-version:x-gm-message-state :content-type; bh=8V9Ac/H2BtehANL5CI1iqkuH0NTaYMCug8rpSJHYylE=; b=PDfDWt8V6Isqxkj8ofmi++CnNsqJe9hr/Y2oTzQ9bzMqcd/bBphWA9HdMRRzUmEoqV tcR1XAY6OTbpGOSkj/1/CSE/lyYdWw8mzMqbkm4xdlENqJCf8S0qVs2qSZgxZ5HOLiDx fthx9oqimqjvXrrSK01WmFKuNSDsxzoLfxNNSRfzxCzVBAFDSXYKq4PMiPu2qtAUZhoG V48nCcDMDUKGAo1vRlmQMZobnnlZA9Ni7xhrVkQQRdbmXgi4d3GoYSZloqWepGOCH/Dj SYvmEIlQWWtEeN31Bna68q4K9ITqEcyfwzp8L074UoYfyWaKpVjXuc8yd0K+Ms5blPIR zp7g== Received: by 10.50.191.233 with SMTP id hb9mr793119igc.44.1333098892424; Fri, 30 Mar 2012 02:14:52 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.5.205 with SMTP id 13csp12463ibw; Fri, 30 Mar 2012 02:14:51 -0700 (PDT) Received: by 10.213.6.212 with SMTP id a20mr353440eba.254.1333098890740; Fri, 30 Mar 2012 02:14:50 -0700 (PDT) Received: from eu1sys200aog113.obsmtp.com (eu1sys200aog113.obsmtp.com. [207.126.144.135]) by mx.google.com with SMTP id j45si2896544eeo.84.2012.03.30.02.14.45 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 30 Mar 2012 02:14:50 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.135 is neither permitted nor denied by best guess record for domain of saugata.das@stericsson.com) client-ip=207.126.144.135; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.135 is neither permitted nor denied by best guess record for domain of saugata.das@stericsson.com) smtp.mail=saugata.das@stericsson.com Received: from beta.dmz-ap.st.com ([138.198.100.35]) (using TLSv1) by eu1sys200aob113.postini.com ([207.126.147.11]) with SMTP ID DSNKT3V5hdCM4v2Vn5wJJUb6lNJADS3xJJlb@postini.com; Fri, 30 Mar 2012 09:14:49 UTC Received: from zeta.dmz-ap.st.com (ns6.st.com [138.198.234.13]) by beta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 205A1AD; Fri, 30 Mar 2012 09:06:19 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-ap.st.com (STMicroelectronics) with ESMTP id C336B927; Fri, 30 Mar 2012 09:14:41 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id C376324C075; Fri, 30 Mar 2012 11:14:35 +0200 (CEST) Received: from localhost (10.201.54.119) by exdcvycastm022.EQ1STM.local (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Fri, 30 Mar 2012 11:14:40 +0200 From: Saugata Das To: Cc: , , Subject: [RFC] MMC-4.5 Power OFF Notify rework Date: Fri, 30 Mar 2012 14:44:17 +0530 Message-ID: <1333098857-30305-1-git-send-email-saugata.das@stericsson.com> X-Mailer: git-send-email 1.7.4.3 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQkaGIAwy7OZ52kr/YZwOBjgsMPk/wvtbVpoEqdWAx+NIb7LiYktJKhjON5EUHWyZH6oh7UK From: Saugata Das This is a rework of the existing POWER OFF NOTIFY patch. The problem with the existing patch comes from the ambiguity on the usage of POWER OFF NOTIFY together with SLEEP and misunderstanding on the usage of MMC_POWER_OFF power_mode from mmc_set_ios in different host controller drivers. This new patch works around this problem by adding a new host CAP, MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND, which when set sends a POWER OFF NOTIFY from mmc_suspend instead of SLEEP. It is expected that host controller drivers will set this CAP, if they switch off both Vcc and Vccq from MMC_POWER_OFF condition within mmc_set_ios. However, note that there is no harm in sending MMC_POWER_NOTIFY even if Vccq is not switched off. This patch also sends POWER OFF NOTIFY from power management routines (e.g. mmc_power_save_host, mmc_pm_notify/PM_SUSPEND_PREPARE, mmc_stop_host), which does reinitialization of the eMMC on the return path of the power management routines (e.g. mmc_power_restore_host, mmc_pm_notify/PM_POST_RESTORE, mmc_start_host). Signed-off-by: Saugata Das Signed-off-by: Girish K S --- drivers/mmc/core/core.c | 36 ++++++++++++++---------------------- drivers/mmc/core/core.h | 1 + drivers/mmc/core/mmc.c | 18 +++++++++++------- include/linux/mmc/host.h | 1 + 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 14f262e..dc85ee1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1096,12 +1096,12 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) mmc_host_clk_release(host); } -static void mmc_poweroff_notify(struct mmc_host *host) +int mmc_poweroff_notify(struct mmc_host *host) { struct mmc_card *card; unsigned int timeout; unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION; - int err = 0; + int err = -EINVAL; card = host->card; mmc_claim_host(host); @@ -1136,6 +1136,7 @@ static void mmc_poweroff_notify(struct mmc_host *host) card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; } mmc_release_host(host); + return err; } /* @@ -1194,30 +1195,12 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { - int err = 0; mmc_host_clk_hold(host); host->ios.clock = 0; host->ios.vdd = 0; /* - * For eMMC 4.5 device send AWAKE command before - * POWER_OFF_NOTIFY command, because in sleep state - * eMMC 4.5 devices respond to only RESET and AWAKE cmd - */ - if (host->card && mmc_card_is_sleep(host->card) && - host->bus_ops->resume) { - err = host->bus_ops->resume(host); - - if (!err) - mmc_poweroff_notify(host); - else - pr_warning("%s: error %d during resume " - "(continue with poweroff sequence)\n", - mmc_hostname(host), err); - } - - /* * Reset ocr mask to be the highest possible voltage supported for * this mmc host. This value will be used at next power up. */ @@ -2076,6 +2059,7 @@ void mmc_stop_host(struct mmc_host *host) host->pm_flags = 0; mmc_bus_get(host); + mmc_poweroff_notify(host); if (host->bus_ops && !host->bus_dead) { /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) @@ -2112,7 +2096,8 @@ int mmc_power_save_host(struct mmc_host *host) if (host->bus_ops->power_save) ret = host->bus_ops->power_save(host); - + host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; + mmc_poweroff_notify(host); mmc_bus_put(host); mmc_power_off(host); @@ -2135,7 +2120,7 @@ int mmc_power_restore_host(struct mmc_host *host) mmc_bus_put(host); return -EINVAL; } - + host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG; mmc_power_up(host); ret = host->bus_ops->power_restore(host); @@ -2157,6 +2142,9 @@ int mmc_card_awake(struct mmc_host *host) if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) err = host->bus_ops->awake(host); + if (!err) + mmc_card_clr_sleep(host->card); + mmc_bus_put(host); return err; @@ -2175,6 +2163,9 @@ int mmc_card_sleep(struct mmc_host *host) if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep) err = host->bus_ops->sleep(host); + if (!err) + mmc_card_set_sleep(host->card); + mmc_bus_put(host); return err; @@ -2393,6 +2384,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->bus_ops->remove(host); mmc_claim_host(host); + mmc_poweroff_notify(host); mmc_detach_bus(host); mmc_power_off(host); mmc_release_host(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 3bdafbc..0bdc0fd 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -45,6 +45,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_power_off(struct mmc_host *host); +int mmc_poweroff_notify(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 02914d6..3e67480 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1338,11 +1338,15 @@ static int mmc_suspend(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - if (mmc_card_can_sleep(host)) { - err = mmc_card_sleep(host); + if (host->caps2 & MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND) { + err = mmc_poweroff_notify(host); if (!err) - mmc_card_set_sleep(host->card); - } else if (!mmc_host_is_spi(host)) + return err; + } + + if (mmc_card_can_sleep(host)) + err = mmc_card_sleep(host); + else if (!mmc_host_is_spi(host)) mmc_deselect_cards(host); host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); mmc_release_host(host); @@ -1364,11 +1368,11 @@ static int mmc_resume(struct mmc_host *host) BUG_ON(!host->card); mmc_claim_host(host); - if (mmc_card_is_sleep(host->card)) { + if (mmc_card_is_sleep(host->card)) err = mmc_card_awake(host); - mmc_card_clr_sleep(host->card); - } else + else err = mmc_init_card(host, host->ocr, host->card); + mmc_release_host(host); return err; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 33a4d08..0e843c7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -237,6 +237,7 @@ struct mmc_host { #define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ #define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */ #define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */ +#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 10) mmc_pm_flag_t pm_caps; /* supported pm features */ unsigned int power_notify_type;