From patchwork Fri Jan 20 14:08:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 9528537 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 43B8060434 for ; Fri, 20 Jan 2017 14:10:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 352E628457 for ; Fri, 20 Jan 2017 14:10:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A43B28686; Fri, 20 Jan 2017 14:10: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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable 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 B1EC728457 for ; Fri, 20 Jan 2017 14:10:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752604AbdATOJg (ORCPT ); Fri, 20 Jan 2017 09:09:36 -0500 Received: from andre.telenet-ops.be ([195.130.132.53]:38722 "EHLO andre.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752364AbdATOIj (ORCPT ); Fri, 20 Jan 2017 09:08:39 -0500 Received: from ayla.of.borg ([84.193.137.253]) by andre.telenet-ops.be with bizsmtp id ae8Y1u00E5UCtCs01e8YT0; Fri, 20 Jan 2017 15:08:36 +0100 Received: from ramsan.of.borg ([192.168.97.29] helo=ramsan) by ayla.of.borg with esmtp (Exim 4.82) (envelope-from ) id 1cUZrk-0001y4-Cc; Fri, 20 Jan 2017 15:08:32 +0100 Received: from geert by ramsan with local (Exim 4.82) (envelope-from ) id 1cUZro-0002cn-EG; Fri, 20 Jan 2017 15:08:36 +0100 From: Geert Uytterhoeven To: Philipp Zabel , Simon Horman , Magnus Damm , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Geert Uytterhoeven Subject: [PATCH 4/8] clk: renesas: cpg-mssr: Add support for reset control Date: Fri, 20 Jan 2017 15:08:22 +0100 Message-Id: <1484921306-9967-5-git-send-email-geert+renesas@glider.be> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484921306-9967-1-git-send-email-geert+renesas@glider.be> References: <1484921306-9967-1-git-send-email-geert+renesas@glider.be> Sender: linux-clk-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-clk@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add optional support for the Reset Control feature of the Renesas Clock Pulse Generator / Module Standby and Software Reset module on R-Car Gen2, R-Car Gen3, and RZ/G1 SoCs. This allows to reset SoC devices using the Reset Controller API. Signed-off-by: Geert Uytterhoeven Acked-by: Philipp Zabel Reviewed-by: Niklas Söderlund Acked-by: Stephen Boyd --- drivers/clk/renesas/renesas-cpg-mssr.c | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index f1161a585c57e433..ea4af714ac14603a 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include @@ -96,6 +98,7 @@ /** * Clock Pulse Generator / Module Standby and Software Reset Private Data * + * @rcdev: Optional reset controller entity * @dev: CPG/MSSR device * @base: CPG/MSSR register block base address * @rmw_lock: protects RMW register accesses @@ -105,6 +108,9 @@ * @last_dt_core_clk: ID of the last Core Clock exported to DT */ struct cpg_mssr_priv { +#ifdef CONFIG_RESET_CONTROLLER + struct reset_controller_dev rcdev; +#endif struct device *dev; void __iomem *base; spinlock_t rmw_lock; @@ -494,6 +500,118 @@ static int __init cpg_mssr_add_clk_domain(struct device *dev, return 0; } +#ifdef CONFIG_RESET_CONTROLLER + +#define rcdev_to_priv(x) container_of(x, struct cpg_mssr_priv, rcdev) + +static int cpg_mssr_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = id / 32; + unsigned int bit = id % 32; + u32 bitmask = BIT(bit); + unsigned long flags; + u32 value; + + dev_dbg(priv->dev, "reset %u%02u\n", reg, bit); + + /* Reset module */ + spin_lock_irqsave(&priv->rmw_lock, flags); + value = readl(priv->base + SRCR(reg)); + value |= bitmask; + writel(value, priv->base + SRCR(reg)); + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + + /* Release module from reset state */ + writel(bitmask, priv->base + SRSTCLR(reg)); + + return 0; +} + +static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = id / 32; + unsigned int bit = id % 32; + unsigned long flags; + u32 value; + + dev_dbg(priv->dev, "assert %u%02u\n", reg, bit); + + spin_lock_irqsave(&priv->rmw_lock, flags); + value = readl(priv->base + SRCR(reg)); + writel(value | BIT(bit), priv->base + SRCR(reg)); + spin_unlock_irqrestore(&priv->rmw_lock, flags); + return 0; +} + +static int cpg_mssr_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = id / 32; + unsigned int bit = id % 32; + + dev_dbg(priv->dev, "deassert %u%02u\n", reg, bit); + + writel(BIT(bit), priv->base + SRSTCLR(reg)); + return 0; +} + +static int cpg_mssr_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = id / 32; + unsigned int bit = id % 32; + + return !!(readl(priv->base + SRCR(reg)) & BIT(bit)); +} + +static const struct reset_control_ops cpg_mssr_reset_ops = { + .reset = cpg_mssr_reset, + .assert = cpg_mssr_assert, + .deassert = cpg_mssr_deassert, + .status = cpg_mssr_status, +}; + +static int cpg_mssr_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct cpg_mssr_priv *priv = rcdev_to_priv(rcdev); + unsigned int unpacked = reset_spec->args[0]; + unsigned int idx = MOD_CLK_PACK(unpacked); + + if (unpacked % 100 > 31 || idx >= rcdev->nr_resets) { + dev_err(priv->dev, "Invalid reset index %u\n", unpacked); + return -EINVAL; + } + + return idx; +} + +static int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv) +{ + priv->rcdev.ops = &cpg_mssr_reset_ops; + priv->rcdev.of_node = priv->dev->of_node; + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.of_xlate = cpg_mssr_reset_xlate; + priv->rcdev.nr_resets = priv->num_mod_clks; + return devm_reset_controller_register(priv->dev, &priv->rcdev); +} + +#else /* !CONFIG_RESET_CONTROLLER */ +static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv) +{ + return 0; +} +#endif /* !CONFIG_RESET_CONTROLLER */ + + static const struct of_device_id cpg_mssr_match[] = { #ifdef CONFIG_ARCH_R8A7743 { @@ -591,6 +709,10 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) if (error) return error; + error = cpg_mssr_reset_controller_register(priv); + if (error) + return error; + return 0; }