From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752550AbdATWFV (ORCPT ); Fri, 20 Jan 2017 17:05:21 -0500 Received: from mail-lf0-f42.google.com ([209.85.215.42]:36799 "EHLO mail-lf0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752330AbdATWD7 (ORCPT ); Fri, 20 Jan 2017 17:03:59 -0500 Date: Fri, 20 Jan 2017 23:03:02 +0100 From: Niklas =?iso-8859-1?Q?S=F6derlund?= To: Geert Uytterhoeven Cc: Philipp Zabel , Simon Horman , Magnus Damm , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland , 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 Subject: Re: [PATCH 4/8] clk: renesas: cpg-mssr: Add support for reset control Message-ID: <20170120220302.GA20610@bigcity.dyn.berto.se> References: <1484921306-9967-1-git-send-email-geert+renesas@glider.be> <1484921306-9967-5-git-send-email-geert+renesas@glider.be> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <1484921306-9967-5-git-send-email-geert+renesas@glider.be> User-Agent: Mutt/1.7.2 (2016-11-26) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Geert, Nice patch! It took me a while to understand why you didn't need to read the register before writing to it in cpg_mssr_deassert() :-) Reviewed-by: Niklas Söderlund On 2017-01-20 15:08:22 +0100, Geert Uytterhoeven wrote: > 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 > --- > 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; > } > > -- > 1.9.1 > -- Regards, Niklas Söderlund