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;
};