From patchwork Wed Mar 8 19:00:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 9611939 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6F6A460417 for ; Wed, 8 Mar 2017 20:48:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6302F28633 for ; Wed, 8 Mar 2017 20:48:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 574CF28635; Wed, 8 Mar 2017 20:48:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B98ED28633 for ; Wed, 8 Mar 2017 20:48:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754523AbdCHUsh (ORCPT ); Wed, 8 Mar 2017 15:48:37 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:33849 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754521AbdCHUsg (ORCPT ); Wed, 8 Mar 2017 15:48:36 -0500 Received: by mail-wm0-f65.google.com with SMTP id u132so7964704wmg.1 for ; Wed, 08 Mar 2017 12:48:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=liabAJ9bH5UetG8VjdnHz9mHBZa9n+RsOeFYitABywY=; b=ESJ8g3jnw/ves4IsC5maGQUrkfWT1tfpfwx+QfeI5aAlxGXzf5ivvRcBVppBBS1NI4 ueEIuLyEcPPUXbfIqW5BZfwmg9BR6wYC/zmCDimiKfHqap9f/KycjWZQhOPkwvj4lPHl jThySOnEomAt5s5xL67hexRfQMSXHZ6OAbMIDWfKfmtsyjT5b9P3BFoB1eRStGNuz3oo azUFJU6OkbSY6dhhGs3VYzAeL6T1SpyjspjzwXJyph0a8tMyorbcvWtj3DBZgdJIf4Ii pILWyEwCPKNTvqlMA9t71FPgbs6g/edNDjytdCoEmlsLXMWG2HDfREDZO4WkoppnU9TR Momg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=liabAJ9bH5UetG8VjdnHz9mHBZa9n+RsOeFYitABywY=; b=j3lQrcNnFO5bcvcCRqoXfY5pw4ln2SAARpd/hAVXyez8oR5LZiP8rkvdoyyhhlCCu8 2jSrn7yCdCgRldCTwwlnPC1aFYoODk+R09A/ngH7Im03LUXS4FbLMSykYLMz2opa8HGb Z5hwII0xXiBuAR9rag1APo+lyKmllo3yk8ojvRmOjzY/cjLelcgmYCxLGLOEtn8lT0M7 66qoI/tBxMpKuMvTJ92Q1W85MYSQrtwePkC1AUqqgeopfznr31Cy61CvervnTIUOMAKR hyQfZkYeqPXF1weYyJ5KMX4gRfOz4RlePscOx5fhCd5YhWRFFGvIAQI3uAwhgo1FbcxK ixuQ== X-Gm-Message-State: AMke39myGjVlUWAVlDPpCztXrCMdrFMdi5x0O07Q0IhpjkUf3TFf7s9gQIPpm9k5Al8FOQ== X-Received: by 10.28.136.13 with SMTP id k13mr7211281wmd.94.1488999642788; Wed, 08 Mar 2017 11:00:42 -0800 (PST) Received: from localhost (port-8170.pppoe.wtnet.de. [84.46.32.10]) by smtp.gmail.com with ESMTPSA id c35sm5312211wra.1.2017.03.08.11.00.41 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 08 Mar 2017 11:00:41 -0800 (PST) From: Thierry Reding To: Adrian Hunter , Ulf Hansson Cc: Jon Hunter , linux-mmc@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH v3 1/2] mmc: tegra: Support module reset Date: Wed, 8 Mar 2017 20:00:39 +0100 Message-Id: <20170308190040.28386-1-thierry.reding@gmail.com> X-Mailer: git-send-email 2.12.0 Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Thierry Reding The device tree binding for the SDHCI controller found on Tegra SoCs specifies that a reset control can be provided by the device tree. No code was ever added to support the module reset, which can cause the driver to try and access registers from a module that's in reset. On most Tegra SoC generations doing so would cause a hang. Note that it's unlikely to see this happen because on most platforms these resets will have been deasserted by the bootloader. However the portability can be improved by making sure the driver deasserts the reset before accessing any registers. Since resets are synchronous on Tegra SoCs, the platform driver needs to implement a custom ->remove() callback now to make sure the clock is disabled after the reset is asserted. Acked-by: Adrian Hunter Signed-off-by: Thierry Reding --- Changes in v3: - use consistent variable names Changes in v2: - assert reset in ->probe() error path - remove unneeded PCI specific quirk drivers/mmc/host/sdhci-tegra.c | 43 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 20b6ff5b4af1..9d31ee8988ef 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,8 @@ struct sdhci_tegra { struct gpio_desc *power_gpio; bool ddr_signaling; bool pad_calib_required; + + struct reset_control *rst; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -489,6 +492,25 @@ static int sdhci_tegra_probe(struct platform_device *pdev) clk_prepare_enable(clk); pltfm_host->clk = clk; + tegra_host->rst = devm_reset_control_get(&pdev->dev, "sdhci"); + if (IS_ERR(tegra_host->rst)) { + rc = PTR_ERR(tegra_host->rst); + dev_err(&pdev->dev, "failed to get reset control: %d\n", rc); + goto err_rst_get; + } + + rc = reset_control_assert(tegra_host->rst); + if (rc) + goto err_rst_get; + + usleep_range(2000, 4000); + + rc = reset_control_deassert(tegra_host->rst); + if (rc) + goto err_rst_get; + + usleep_range(2000, 4000); + rc = sdhci_add_host(host); if (rc) goto err_add_host; @@ -496,6 +518,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev) return 0; err_add_host: + reset_control_assert(tegra_host->rst); +err_rst_get: clk_disable_unprepare(pltfm_host->clk); err_clk_get: err_power_req: @@ -504,6 +528,23 @@ static int sdhci_tegra_probe(struct platform_device *pdev) return rc; } +static int sdhci_tegra_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + + sdhci_remove_host(host, 0); + + reset_control_assert(tegra_host->rst); + usleep_range(2000, 4000); + clk_disable_unprepare(pltfm_host->clk); + + sdhci_pltfm_free(pdev); + + return 0; +} + static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", @@ -511,7 +552,7 @@ static struct platform_driver sdhci_tegra_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_tegra_probe, - .remove = sdhci_pltfm_unregister, + .remove = sdhci_tegra_remove, }; module_platform_driver(sdhci_tegra_driver);