From patchwork Fri Aug 22 13:47:52 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuvaraj CD X-Patchwork-Id: 4763881 Return-Path: X-Original-To: patchwork-linux-samsung-soc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 4D94D9F37E for ; Fri, 22 Aug 2014 13:48:34 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1C1B22017A for ; Fri, 22 Aug 2014 13:48:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D886320136 for ; Fri, 22 Aug 2014 13:48:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756375AbaHVNsb (ORCPT ); Fri, 22 Aug 2014 09:48:31 -0400 Received: from mail-pd0-f169.google.com ([209.85.192.169]:62008 "EHLO mail-pd0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756367AbaHVNsa (ORCPT ); Fri, 22 Aug 2014 09:48:30 -0400 Received: by mail-pd0-f169.google.com with SMTP id y10so16125917pdj.28 for ; Fri, 22 Aug 2014 06:48:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Rhr+XwJxRe8lxcE7KlwXieLkplcJFIVDVf45euabHqE=; b=fH9sv119vsH5uWG2RYs+1FA4xyVJtKr7lZ8/DUklwBanjEWquo+aqXc2LhheZvdZTw PH6/E5N5Ljue6WCYJ13rc+2QGqzTRMefEqFrhIuHQVUda+fJU1Gq25h+IUTUCwPqdGoh vuwY2G3ttoJ+hCiRnIh1EaH2Ejc/NKMVVRNtbygIuGHcyAYBn6yIlInFXllysnP5ZUiF FKZEDt4QSW2haW0rIQcCcwDkJSdiAFUBkm2s4zRRjLzEKvD1UXxvFF1OfFxrwQz/0Qk8 G1eb4W26l7rspqkom2EzF94zsCXtpClUMmDEsi0uRpXy4dxiVc1RPzICoEzQt9S2Y+G5 KHhQ== X-Received: by 10.68.162.227 with SMTP id yd3mr6662741pbb.19.1408715309752; Fri, 22 Aug 2014 06:48:29 -0700 (PDT) Received: from localhost.localdomain ([14.140.216.146]) by mx.google.com with ESMTPSA id mq6sm7694422pdb.82.2014.08.22.06.48.24 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 22 Aug 2014 06:48:29 -0700 (PDT) From: Yuvaraj Kumar C D X-Google-Original-From: Yuvaraj Kumar C D To: linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, dianders@google.com, dianders@chromium.org, jh80.chung@samsung.com, cjb@laptop.org, tgih.jun@samsung.com, linux-mmc@vger.kernel.org, ulf.hansson@linaro.org Cc: sonnyrao@chromium.org, t.figa@samsung.com, kgene.kim@samsung.com, joshi@samsung.com, prashanth.g@samsung.com, alim.akhtar@samsung.com, javier.martinez@collabora.co.uk, a.kesavan@samsung.com, Yuvaraj Kumar C D Subject: [PATCH V2 3/3] mmc: dw_mmc: Dont cut off vqmmc and vmmc Date: Fri, 22 Aug 2014 19:17:52 +0530 Message-Id: <1408715272-13833-4-git-send-email-yuvaraj.cd@samsung.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1408715272-13833-1-git-send-email-yuvaraj.cd@samsung.com> References: <1408715272-13833-1-git-send-email-yuvaraj.cd@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Exynos 5250 and 5420 based boards uses built-in CD# line for card detection.But unfortunately CD# line is on the same voltage rails as of I/O voltage rails. When we cut off vqmmc,the consequent card detection will break in these boards. These hosts (obviously) need to keep vqmmc (and thus vmmc) on all the time, even when the mmc core tells them to power off. However, one problem is that these cards won't properly handle mmc_power_cycle(). That's needed to handle error cases when trying to switch voltages (see 0797e5f mmc:core: Fixup signal voltage switch). This patch adds a new MMC_POWER_OFF_HARD mode when it's doing a power cycle. This mode differs from the normal MMC_POWER_OFF mode in that the mmc core will promise to power the slot back on before it expects the host to detect card insertion or removal. Also if we let alone the vqmmc turned on when vmmc turned off, the card could have half way powered and this can damage the card. So this patch adds a check so that, if the board used the built-in card detection mechanism i.e through CDETECT, it will not turned down vqmmc and vmmc both. Signed-off-by: Yuvaraj Kumar C D Signed-off-by: Doug Anderson --- changes from v1: 1.added a new MMC_POWER_OFF_HARD mode as per Doug Anderson's suggestion. 2.added dw_mci_exynos_post_init() to perform the host specific post initialisation. 3.added a new flag MMC_CAP2_CD_NEEDS_POWER for host->caps2. drivers/mmc/core/core.c | 16 ++++++++++++++-- drivers/mmc/core/debugfs.c | 3 +++ drivers/mmc/host/dw_mmc-exynos.c | 12 ++++++++++++ drivers/mmc/host/dw_mmc.c | 25 +++++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 2 ++ include/linux/mmc/host.h | 2 ++ 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 68f5f4b..79ced36 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1564,9 +1564,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_host_clk_release(host); } -void mmc_power_off(struct mmc_host *host) +void _mmc_power_off(struct mmc_host *host, unsigned char power_mode) { - if (host->ios.power_mode == MMC_POWER_OFF) + if (host->ios.power_mode == power_mode) return; mmc_host_clk_hold(host); @@ -1579,6 +1579,7 @@ void mmc_power_off(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; } host->ios.power_mode = MMC_POWER_OFF; + host->ios.power_mode = power_mode; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); @@ -1593,9 +1594,20 @@ void mmc_power_off(struct mmc_host *host) mmc_host_clk_release(host); } +void mmc_power_off(struct mmc_host *host) +{ + _mmc_power_off(host, MMC_POWER_OFF); +} + void mmc_power_cycle(struct mmc_host *host, u32 ocr) { mmc_power_off(host); + /* If host normally ignores MMC_POWER_OFF, tell it to pay attention */ + if (host->caps2 & MMC_CAP2_CD_NEEDS_POWER) + _mmc_power_off(host, MMC_POWER_OFF_HARD); + else + _mmc_power_off(host, MMC_POWER_OFF); + /* Wait at least 1 ms according to SD spec */ mmc_delay(1); mmc_power_up(host, ocr); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 91eb162..3d9c5a3 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -108,6 +108,9 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_POWER_ON: str = "on"; break; + case MMC_POWER_OFF_HARD: + str = "hard off"; + break; default: str = "invalid"; break; diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0fbc53a..4e26049 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "dw_mmc.h" @@ -217,6 +218,16 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) } } +static void dw_mci_exynos_post_init(struct dw_mci_slot *slot) +{ + struct dw_mci_board *brd = slot->host->pdata; + struct mmc_host *mmc = slot->mmc; + + if (!(brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) && + IS_ERR_VALUE(mmc_gpio_get_cd(mmc))) + mmc->caps2 |= MMC_CAP2_CD_NEEDS_POWER; +} + static int dw_mci_exynos_parse_dt(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv; @@ -399,6 +410,7 @@ static const struct dw_mci_drv_data exynos_drv_data = { .prepare_command = dw_mci_exynos_prepare_command, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, + .post_init = dw_mci_exynos_post_init, .execute_tuning = dw_mci_exynos_execute_tuning, }; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index f20b4b8..6f2c681 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -972,6 +972,22 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_bh(&host->lock); } +/* + * some of the boards use controller CD line for card detection.Unfortunately + * CD line is bind to the same volatge domain as of the IO lines.If we turn off + * IO voltage domain, CD line wont work. + * Return true when controller CD line is used for card detection or return + * false. + */ +static bool dw_mci_builtin_cd(struct dw_mci_slot *slot) +{ + struct dw_mci_board *brd = slot->host->pdata; + struct mmc_host *mmc = slot->mmc; + + return (!(brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) && + IS_ERR_VALUE(mmc_gpio_get_cd(mmc))) ? 1 : 0; +} + static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1043,6 +1059,10 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_OFF: + if (dw_mci_builtin_cd(slot) && + !test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) + return; + if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); @@ -1055,6 +1075,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) regs &= ~(1 << slot->id); mci_writel(slot->host, PWREN, regs); break; + case MMC_POWER_OFF_HARD: + break; default: break; } @@ -2310,6 +2332,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) else clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + if (drv_data && drv_data->post_init) + drv_data->post_init(slot); + ret = mmc_add_host(mmc); if (ret) goto err_setup_bus; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 01b99e8..a3c2628 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -250,6 +250,7 @@ struct dw_mci_tuning_data { * @prepare_command: handle CMD register extensions. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. + * @post_init: implementation specific post initialization. * @execute_tuning: implementation specific tuning procedure. * * Provide controller implementation specific extensions. The usage of this @@ -263,6 +264,7 @@ struct dw_mci_drv_data { void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); + void (*post_init)(struct dw_mci_slot *slot); int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode, struct dw_mci_tuning_data *tuning_data); }; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 4cbf614..5eb24ff 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -42,6 +42,7 @@ struct mmc_ios { #define MMC_POWER_OFF 0 #define MMC_POWER_UP 1 #define MMC_POWER_ON 2 +#define MMC_POWER_OFF_HARD 3 unsigned char bus_width; /* data bus width */ @@ -283,6 +284,7 @@ struct mmc_host { #define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ MMC_CAP2_HS400_1_2V) #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) +#define MMC_CAP2_CD_NEEDS_POWER (1 << 18) /* Card detect needs power */ mmc_pm_flag_t pm_caps; /* supported pm features */