clk: renesas: Add PE clock handling

The PE clock have two parents, add support for picking the correct
one and deriving the clock from it.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c
index f255059..99698b1 100644
--- a/drivers/clk/renesas/clk-rcar-gen3.c
+++ b/drivers/clk/renesas/clk-rcar-gen3.c
@@ -85,6 +85,28 @@
 	CPG_SD_DIV_TABLE_DATA(1,        0,        4,          0,       32),
 };
 
+static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
+			       struct cpg_mssr_info *info, struct clk *parent)
+{
+	const struct cpg_core_clk *core;
+	int ret;
+
+	if (!renesas_clk_is_mod(clk)) {
+		ret = renesas_clk_get_core(clk, info, &core);
+		if (ret)
+			return ret;
+
+		if (core->type == CLK_TYPE_GEN3_PE) {
+			parent->dev = clk->dev;
+			parent->id = core->parent >> (priv->sscg ? 16 : 0);
+			parent->id &= 0xffff;
+			return 0;
+		}
+	}
+
+	return renesas_clk_get_parent(clk, info, parent);
+}
+
 static int gen3_clk_setup_sdif_div(struct clk *clk)
 {
 	struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
@@ -93,7 +115,7 @@
 	struct clk parent;
 	int ret;
 
-	ret = renesas_clk_get_parent(clk, info, &parent);
+	ret = gen3_clk_get_parent(priv, clk, info, &parent);
 	if (ret) {
 		printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
 		return ret;
@@ -142,13 +164,13 @@
 	const struct cpg_core_clk *core;
 	const struct rcar_gen3_cpg_pll_config *pll_config =
 					priv->cpg_pll_config;
-	u32 value, mult, prediv, postdiv;
+	u32 value, mult, div, prediv, postdiv;
 	u64 rate = 0;
 	int i, ret;
 
 	debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
 
-	ret = renesas_clk_get_parent(clk, info, &parent);
+	ret = gen3_clk_get_parent(priv, clk, info, &parent);
 	if (ret) {
 		printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret);
 		return ret;
@@ -233,13 +255,21 @@
 		return rate;
 
 	case CLK_TYPE_FF:
-	case CLK_TYPE_GEN3_PE:		/* FIXME */
 		rate = (gen3_clk_get_rate64(&parent) * core->mult) / core->div;
 		debug("%s[%i] FIXED clk: parent=%i mul=%i div=%i => rate=%llu\n",
 		      __func__, __LINE__,
 		      core->parent, core->mult, core->div, rate);
 		return rate;
 
+	case CLK_TYPE_GEN3_PE:
+		div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff;
+		rate = gen3_clk_get_rate64(&parent) / div;
+		debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n",
+		      __func__, __LINE__,
+		      (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff,
+		      div, rate);
+		return rate;
+
 	case CLK_TYPE_GEN3_SD:		/* FIXME */
 		value = readl(priv->base + core->offset);
 		value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK;
@@ -351,6 +381,8 @@
 	if (!priv->cpg_pll_config->extal_div)
 		return -EINVAL;
 
+	priv->sscg = !(cpg_mode & BIT(12));
+
 	ret = clk_get_by_name(dev, "extal", &priv->clk_extal);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h
index 2f410df..58e71f3 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.h
+++ b/drivers/clk/renesas/rcar-gen3-cpg.h
@@ -31,8 +31,9 @@
 	DEF_BASE(_name, _id, CLK_TYPE_GEN3_RPC, _parent, .offset = _offset)
 #define DEF_GEN3_PE(_name, _id, _parent_sscg, _div_sscg, _parent_clean, \
 		    _div_clean) \
-	DEF_BASE(_name, _id, CLK_TYPE_FF,			\
-		 (_parent_clean), .div = (_div_clean), 1)
+	DEF_BASE(_name, _id, CLK_TYPE_GEN3_PE,			\
+		 (_parent_sscg) << 16 | (_parent_clean),	\
+		 .div = (_div_sscg) << 16 | (_div_clean))
 
 struct rcar_gen3_cpg_pll_config {
 	u8 extal_div;
@@ -49,6 +50,7 @@
 	struct cpg_mssr_info	*info;
 	struct clk		clk_extal;
 	struct clk		clk_extalr;
+	bool			sscg;
 	const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
 };