summaryrefslogtreecommitdiffstats
path: root/drivers/clk/renesas/renesas-cpg-mssr.c
diff options
context:
space:
mode:
authorChris Brandt <chris.brandt@renesas.com>2018-09-07 18:58:49 +0200
committerGeert Uytterhoeven <geert+renesas@glider.be>2018-09-11 12:01:07 +0200
commitfde35c9c7db5732cc1fbd89fa5eba5a9e0b25f6e (patch)
treea63b445c8cc26e2c79c7c743ab2009be37fe87a9 /drivers/clk/renesas/renesas-cpg-mssr.c
parentclk: renesas: r8a77970: Add TMU clocks (diff)
downloadlinux-fde35c9c7db5732cc1fbd89fa5eba5a9e0b25f6e.tar.xz
linux-fde35c9c7db5732cc1fbd89fa5eba5a9e0b25f6e.zip
clk: renesas: cpg-mssr: Add R7S9210 support
Add support for the R7S9210 (RZ/A2) Clock Pulse Generator and Module Standby. The Module Standby HW in the RZ/A series is very close to R-Car HW, except for how the registers are laid out. The MSTP registers are only 8-bits wide, there are no status registers (MSTPSR), and the register offsets are a little different. Since the RZ/A hardware manuals refer to these registers as the Standby Control Registers, we'll use that name to distinguish the RZ/A type from the R-Car type. Signed-off-by: Chris Brandt <chris.brandt@renesas.com> Acked-by: Rob Herring <robh@kernel.org> # DT bits Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Diffstat (limited to 'drivers/clk/renesas/renesas-cpg-mssr.c')
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c81
1 files changed, 69 insertions, 12 deletions
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index f90b0d0ba46a..b97e0e3ff0b1 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -73,6 +73,17 @@ static const u16 smstpcr[] = {
#define SMSTPCR(i) smstpcr[i]
+/*
+ * Standby Control Register offsets (RZ/A)
+ * Base address is FRQCR register
+ */
+
+static const u16 stbcr[] = {
+ 0xFFFF/*dummy*/, 0x010, 0x014, 0x410, 0x414, 0x418, 0x41C, 0x420,
+ 0x424, 0x428, 0x42C,
+};
+
+#define STBCR(i) stbcr[i]
/*
* Software Reset Register offsets
@@ -110,6 +121,7 @@ static const u16 srcr[] = {
* @notifiers: Notifier chain to save/restore clock state for system resume
* @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control
* @smstpcr_saved[].val: Saved values of SMSTPCR[]
+ * @stbyctrl: This device has Standby Control Registers
*/
struct cpg_mssr_priv {
#ifdef CONFIG_RESET_CONTROLLER
@@ -123,6 +135,7 @@ struct cpg_mssr_priv {
unsigned int num_core_clks;
unsigned int num_mod_clks;
unsigned int last_dt_core_clk;
+ bool stbyctrl;
struct raw_notifier_head notifiers;
struct {
@@ -162,16 +175,29 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
enable ? "ON" : "OFF");
spin_lock_irqsave(&priv->rmw_lock, flags);
- value = readl(priv->base + SMSTPCR(reg));
- if (enable)
- value &= ~bitmask;
- else
- value |= bitmask;
- writel(value, priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl) {
+ value = readb(priv->base + STBCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ writeb(value, priv->base + STBCR(reg));
+
+ /* dummy read to ensure write has completed */
+ readb(priv->base + STBCR(reg));
+ barrier_data(priv->base + STBCR(reg));
+ } else {
+ value = readl(priv->base + SMSTPCR(reg));
+ if (enable)
+ value &= ~bitmask;
+ else
+ value |= bitmask;
+ writel(value, priv->base + SMSTPCR(reg));
+ }
spin_unlock_irqrestore(&priv->rmw_lock, flags);
- if (!enable)
+ if (!enable || priv->stbyctrl)
return 0;
for (i = 1000; i > 0; --i) {
@@ -205,7 +231,10 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
struct cpg_mssr_priv *priv = clock->priv;
u32 value;
- value = readl(priv->base + MSTPSR(clock->index / 32));
+ if (priv->stbyctrl)
+ value = readb(priv->base + STBCR(clock->index / 32));
+ else
+ value = readl(priv->base + MSTPSR(clock->index / 32));
return !(value & BIT(clock->index % 32));
}
@@ -226,6 +255,7 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
unsigned int idx;
const char *type;
struct clk *clk;
+ int range_check;
switch (clkspec->args[0]) {
case CPG_CORE:
@@ -240,8 +270,14 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
case CPG_MOD:
type = "module";
- idx = MOD_CLK_PACK(clkidx);
- if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
+ if (priv->stbyctrl) {
+ idx = MOD_CLK_PACK_10(clkidx);
+ range_check = 7 - (clkidx % 10);
+ } else {
+ idx = MOD_CLK_PACK(clkidx);
+ range_check = 31 - (clkidx % 100);
+ }
+ if (range_check < 0 || idx >= priv->num_mod_clks) {
dev_err(dev, "Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
@@ -646,6 +682,12 @@ static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
static const struct of_device_id cpg_mssr_match[] = {
+#ifdef CONFIG_CLK_R7S9210
+ {
+ .compatible = "renesas,r7s9210-cpg-mssr",
+ .data = &r7s9210_cpg_mssr_info,
+ },
+#endif
#ifdef CONFIG_CLK_R8A7743
{
.compatible = "renesas,r8a7743-cpg-mssr",
@@ -791,13 +833,23 @@ static int cpg_mssr_resume_noirq(struct device *dev)
if (!mask)
continue;
- oldval = readl(priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl)
+ oldval = readb(priv->base + STBCR(reg));
+ else
+ oldval = readl(priv->base + SMSTPCR(reg));
newval = oldval & ~mask;
newval |= priv->smstpcr_saved[reg].val & mask;
if (newval == oldval)
continue;
- writel(newval, priv->base + SMSTPCR(reg));
+ if (priv->stbyctrl) {
+ writeb(newval, priv->base + STBCR(reg));
+ /* dummy read to ensure write has completed */
+ readb(priv->base + STBCR(reg));
+ barrier_data(priv->base + STBCR(reg));
+ continue;
+ } else
+ writel(newval, priv->base + SMSTPCR(reg));
/* Wait until enabled clocks are really enabled */
mask &= ~priv->smstpcr_saved[reg].val;
@@ -869,6 +921,7 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
RAW_INIT_NOTIFIER_HEAD(&priv->notifiers);
+ priv->stbyctrl = info->stbyctrl;
for (i = 0; i < nclks; i++)
clks[i] = ERR_PTR(-ENOENT);
@@ -894,6 +947,10 @@ static int __init cpg_mssr_probe(struct platform_device *pdev)
if (error)
return error;
+ /* Reset Controller not supported for Standby Control SoCs */
+ if (info->stbyctrl)
+ return 0;
+
error = cpg_mssr_reset_controller_register(priv);
if (error)
return error;