aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/clk/clk-composite.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/clk/clk-composite.c')
-rw-r--r--roms/u-boot/drivers/clk/clk-composite.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/clk/clk-composite.c b/roms/u-boot/drivers/clk/clk-composite.c
new file mode 100644
index 000000000..bb5351ebc
--- /dev/null
+++ b/roms/u-boot/drivers/clk/clk-composite.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <clk-uclass.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <linux/clk-provider.h>
+#include <clk.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+#define UBOOT_DM_CLK_COMPOSITE "clk_composite"
+
+static u8 clk_composite_get_parent(struct clk *clk)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ struct clk *mux = composite->mux;
+
+ if (mux)
+ return clk_mux_get_parent(mux);
+ else
+ return 0;
+}
+
+static int clk_composite_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ const struct clk_ops *mux_ops = composite->mux_ops;
+ struct clk *mux = composite->mux;
+
+ if (!mux || !mux_ops)
+ return -ENOSYS;
+
+ return mux_ops->set_parent(mux, parent);
+}
+
+static unsigned long clk_composite_recalc_rate(struct clk *clk)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ const struct clk_ops *rate_ops = composite->rate_ops;
+ struct clk *rate = composite->rate;
+
+ if (rate && rate_ops)
+ return rate_ops->get_rate(rate);
+ else
+ return clk_get_parent_rate(clk);
+}
+
+static ulong clk_composite_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ const struct clk_ops *rate_ops = composite->rate_ops;
+ struct clk *clk_rate = composite->rate;
+
+ if (rate && rate_ops)
+ return rate_ops->set_rate(clk_rate, rate);
+ else
+ return clk_get_rate(clk);
+}
+
+static int clk_composite_enable(struct clk *clk)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk *gate = composite->gate;
+
+ if (gate && gate_ops)
+ return gate_ops->enable(gate);
+ else
+ return 0;
+}
+
+static int clk_composite_disable(struct clk *clk)
+{
+ struct clk_composite *composite = to_clk_composite(clk_dev_binded(clk) ?
+ (struct clk *)dev_get_clk_ptr(clk->dev) : clk);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk *gate = composite->gate;
+
+ if (gate && gate_ops)
+ return gate_ops->disable(gate);
+ else
+ return 0;
+}
+
+struct clk *clk_register_composite(struct device *dev, const char *name,
+ const char * const *parent_names,
+ int num_parents, struct clk *mux,
+ const struct clk_ops *mux_ops,
+ struct clk *rate,
+ const struct clk_ops *rate_ops,
+ struct clk *gate,
+ const struct clk_ops *gate_ops,
+ unsigned long flags)
+{
+ struct clk *clk;
+ struct clk_composite *composite;
+ int ret;
+
+ if (!num_parents || (num_parents != 1 && !mux))
+ return ERR_PTR(-EINVAL);
+
+ composite = kzalloc(sizeof(*composite), GFP_KERNEL);
+ if (!composite)
+ return ERR_PTR(-ENOMEM);
+
+ if (mux && mux_ops) {
+ composite->mux = mux;
+ composite->mux_ops = mux_ops;
+ mux->data = (ulong)composite;
+ }
+
+ if (rate && rate_ops) {
+ if (!rate_ops->get_rate) {
+ clk = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ composite->rate = rate;
+ composite->rate_ops = rate_ops;
+ rate->data = (ulong)composite;
+ }
+
+ if (gate && gate_ops) {
+ if (!gate_ops->enable || !gate_ops->disable) {
+ clk = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ composite->gate = gate;
+ composite->gate_ops = gate_ops;
+ gate->data = (ulong)composite;
+ }
+
+ clk = &composite->clk;
+ clk->flags = flags;
+ ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
+ parent_names[clk_composite_get_parent(clk)]);
+ if (ret) {
+ clk = ERR_PTR(ret);
+ goto err;
+ }
+
+ if (composite->mux)
+ composite->mux->dev = clk->dev;
+ if (composite->rate)
+ composite->rate->dev = clk->dev;
+ if (composite->gate)
+ composite->gate->dev = clk->dev;
+
+ return clk;
+
+err:
+ kfree(composite);
+ return clk;
+}
+
+static const struct clk_ops clk_composite_ops = {
+ .set_parent = clk_composite_set_parent,
+ .get_rate = clk_composite_recalc_rate,
+ .set_rate = clk_composite_set_rate,
+ .enable = clk_composite_enable,
+ .disable = clk_composite_disable,
+};
+
+U_BOOT_DRIVER(clk_composite) = {
+ .name = UBOOT_DM_CLK_COMPOSITE,
+ .id = UCLASS_CLK,
+ .ops = &clk_composite_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};