summaryrefslogtreecommitdiffstats
path: root/drivers/clk/zynqmp/clk-gate-zynqmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/zynqmp/clk-gate-zynqmp.c')
-rw-r--r--drivers/clk/zynqmp/clk-gate-zynqmp.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c
new file mode 100644
index 0000000000..6f03357768
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Zynq UltraScale+ MPSoC Clock Gate
+ *
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <m.tretter@pengutronix.de>
+ *
+ * Based on the Linux driver in drivers/clk/zynqmp/
+ *
+ * Copyright (C) 2016-2018 Xilinx
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <mach/firmware-zynqmp.h>
+
+#include "clk-zynqmp.h"
+
+struct zynqmp_clk_gate {
+ struct clk clk;
+ unsigned int clk_id;
+ const char *parent;
+ const struct zynqmp_eemi_ops *ops;
+};
+
+#define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, clk)
+
+static int zynqmp_clk_gate_enable(struct clk *clk)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(clk);
+
+ return gate->ops->clock_enable(gate->clk_id);
+}
+
+static void zynqmp_clk_gate_disable(struct clk *clk)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(clk);
+
+ gate->ops->clock_disable(gate->clk_id);
+}
+
+static int zynqmp_clk_gate_is_enabled(struct clk *clk)
+{
+ struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(clk);
+ u32 state;
+ int ret;
+ const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+
+ ret = eemi_ops->clock_getstate(gate->clk_id, &state);
+ if (ret)
+ return -EIO;
+
+ return !!state;
+}
+
+static const struct clk_ops zynqmp_clk_gate_ops = {
+ .set_rate = clk_parent_set_rate,
+ .round_rate = clk_parent_round_rate,
+ .enable = zynqmp_clk_gate_enable,
+ .disable = zynqmp_clk_gate_disable,
+ .is_enabled = zynqmp_clk_gate_is_enabled,
+};
+
+struct clk *zynqmp_clk_register_gate(const char *name,
+ unsigned int clk_id,
+ const char **parents,
+ unsigned int num_parents,
+ const struct clock_topology *nodes)
+{
+ struct zynqmp_clk_gate *gate;
+ int ret;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->clk_id = clk_id;
+ gate->ops = zynqmp_pm_get_eemi_ops();
+ gate->parent = strdup(parents[0]);
+
+ gate->clk.name = strdup(name);
+ gate->clk.ops = &zynqmp_clk_gate_ops;
+ gate->clk.flags = nodes->flag | CLK_SET_RATE_PARENT;
+ gate->clk.parent_names = &gate->parent;
+ gate->clk.num_parents = 1;
+
+ ret = clk_register(&gate->clk);
+ if (ret) {
+ kfree(gate);
+ return ERR_PTR(ret);
+ }
+
+ return &gate->clk;
+}