From patchwork Tue Aug 25 09:05:35 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kishon Vijay Abraham I X-Patchwork-Id: 7069871 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9A4679F374 for ; Tue, 25 Aug 2015 09:11:25 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id ACF482088F for ; Tue, 25 Aug 2015 09:11:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 95829207EA for ; Tue, 25 Aug 2015 09:11:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755222AbbHYJK0 (ORCPT ); Tue, 25 Aug 2015 05:10:26 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:45914 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932538AbbHYJGE (ORCPT ); Tue, 25 Aug 2015 05:06:04 -0400 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id t7P95xdh012214; Tue, 25 Aug 2015 04:05:59 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id t7P95xLU023283; Tue, 25 Aug 2015 04:05:59 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.224.2; Tue, 25 Aug 2015 04:05:59 -0500 Received: from a0393678ub.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id t7P95h4c031149; Tue, 25 Aug 2015 04:05:56 -0500 From: Kishon Vijay Abraham I To: , , , , , , CC: , Subject: [PATCH v2 04/11] mmc: host: omap_hsmmc: add voltage switch support for UHS SD card Date: Tue, 25 Aug 2015 14:35:35 +0530 Message-ID: <1440493542-26150-5-git-send-email-kishon@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1440493542-26150-1-git-send-email-kishon@ti.com> References: <1440493542-26150-1-git-send-email-kishon@ti.com> MIME-Version: 1.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 From: Balaji T K UHS sd card i/o data line can operate at 3V and 1.8V on UHS speed modes. Add support for signal voltage switch and check for card_busy. Signed-off-by: Balaji T K Signed-off-by: Sourav Poddar [kishon@ti.com : cleanup the voltage switch sequence] Signed-off-by: Kishon Vijay Abraham I --- drivers/mmc/host/omap_hsmmc.c | 129 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d3fe0f8..7dac486 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -112,6 +112,9 @@ /* PSTATE */ #define DLEV_DAT(x) (1 << (20 + (x))) +/* AC12 */ +#define AC12_V1V8_SIGEN (1 << 19) + /* Interrupt masks for IE and ISE register */ #define CC_EN (1 << 0) #define TC_EN (1 << 1) @@ -151,6 +154,12 @@ #define VDD_1V8 1800000 /* 180000 uV */ #define VDD_3V0 3000000 /* 300000 uV */ #define VDD_165_195 (ffs(MMC_VDD_165_195) - 1) +#define VDD_30_31 (ffs(MMC_VDD_30_31) - 1) + +#define CON_CLKEXTFREE (1 << 16) +#define CON_PADEN (1 << 15) +#define PSTATE_CLEV (1 << 24) +#define PSTATE_DLEV (0xF << 20) /* * One controller can have multiple slots, like on some omap boards using @@ -1860,6 +1869,124 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, return blk_size; } +static int omap_hsmmc_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct omap_hsmmc_host *host; + u32 val = 0; + int ret = 0; + + host = mmc_priv(mmc); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + val = OMAP_HSMMC_READ(host->base, CAPA); + if (!(val & VS30)) + return -EOPNOTSUPP; + + omap_hsmmc_conf_bus_power(host, ios->signal_voltage); + + val = OMAP_HSMMC_READ(host->base, AC12); + val &= ~AC12_V1V8_SIGEN; + OMAP_HSMMC_WRITE(host->base, AC12, val); + + ret = mmc_pdata(host)->set_power(host->dev, 1, VDD_30_31); + if (ret) { + dev_dbg(mmc_dev(host->mmc), "failed to switch to 3v\n"); + return ret; + } + + dev_dbg(mmc_dev(host->mmc), " i/o voltage switch to 3V\n"); + } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + val = OMAP_HSMMC_READ(host->base, CAPA); + if (!(val & VS18)) + return -EOPNOTSUPP; + + omap_hsmmc_conf_bus_power(host, ios->signal_voltage); + + val = OMAP_HSMMC_READ(host->base, AC12); + val |= AC12_V1V8_SIGEN; + OMAP_HSMMC_WRITE(host->base, AC12, val); + + ret = mmc_pdata(host)->set_power(host->dev, 1, VDD_165_195); + if (ret < 0) { + dev_dbg(mmc_dev(host->mmc), "failed to switch 1.8v\n"); + return ret; + } + } else { + return -EOPNOTSUPP; + } + + return 0; +} + +static int omap_hsmmc_card_busy_low(struct omap_hsmmc_host *host) +{ + u32 val; + unsigned long timeout; + + val = OMAP_HSMMC_READ(host->base, CON); + val &= ~CON_CLKEXTFREE; + val |= CON_PADEN; + OMAP_HSMMC_WRITE(host->base, CON, val); + + timeout = jiffies + msecs_to_jiffies(1); + do { + val = OMAP_HSMMC_READ(host->base, PSTATE); + if (!(val & (PSTATE_CLEV | PSTATE_DLEV))) + return true; + + usleep_range(100, 200); + } while (!time_after(jiffies, timeout)); + + dev_err(mmc_dev(host->mmc), "timeout : i/o low 0x%x\n", val); + + return false; +} + +static int omap_hsmmc_card_busy_high(struct omap_hsmmc_host *host) +{ + u32 val; + unsigned long timeout; + + val = OMAP_HSMMC_READ(host->base, CON); + val |= CLKEXTFREE; + OMAP_HSMMC_WRITE(host->base, CON, val); + + timeout = jiffies + msecs_to_jiffies(1); + do { + val = OMAP_HSMMC_READ(host->base, PSTATE); + if ((val & PSTATE_CLEV) && (val & PSTATE_DLEV)) { + val = OMAP_HSMMC_READ(host->base, CON); + val &= ~(CON_CLKEXTFREE | CON_PADEN); + OMAP_HSMMC_WRITE(host->base, CON, val); + return false; + } + + usleep_range(100, 200); + } while (!time_after(jiffies, timeout)); + + dev_err(mmc_dev(host->mmc), "timeout : i/o high 0x%x\n", val); + + return true; +} + +static int omap_hsmmc_card_busy(struct mmc_host *mmc) +{ + struct omap_hsmmc_host *host; + u32 val; + int ret; + + host = mmc_priv(mmc); + + val = OMAP_HSMMC_READ(host->base, AC12); + if (val & AC12_V1V8_SIGEN) + ret = omap_hsmmc_card_busy_high(host); + else + ret = omap_hsmmc_card_busy_low(host); + + return ret; +} + static struct mmc_host_ops omap_hsmmc_ops = { .post_req = omap_hsmmc_post_req, .pre_req = omap_hsmmc_pre_req, @@ -1869,6 +1996,8 @@ static struct mmc_host_ops omap_hsmmc_ops = { .get_ro = mmc_gpio_get_ro, .init_card = omap_hsmmc_init_card, .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, + .start_signal_voltage_switch = omap_hsmmc_start_signal_voltage_switch, + .card_busy = omap_hsmmc_card_busy, }; #ifdef CONFIG_DEBUG_FS