Import clk composite clk support from Linux Kernel 5.1-rc5

Signed-off-by: Peng Fan <peng....@nxp.com>
---
 drivers/clk/Kconfig          |  14 ++++
 drivers/clk/Makefile         |   1 +
 drivers/clk/clk-composite.c  | 165 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk-provider.h |  22 ++++++
 4 files changed, 202 insertions(+)
 create mode 100644 drivers/clk/clk-composite.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9df3bc731a..3735e235f5 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -53,6 +53,13 @@ config SPL_CLK_CCF
          Enable this option if you want to (re-)use the Linux kernel's Common
          Clock Framework [CCF] code in U-Boot's SPL.
 
+config SPL_CLK_COMPOSITE_CCF
+       bool "SPL Common Clock Framework [CCF] composite clk support "
+       depends on SPL_CLK_CCF
+       help
+         Enable this option if you want to (re-)use the Linux kernel's Common
+         Clock Framework [CCF] composite code in U-Boot's SPL.
+
 config CLK_CCF
        bool "Common Clock Framework [CCF] support "
        depends on CLK
@@ -60,6 +67,13 @@ config CLK_CCF
          Enable this option if you want to (re-)use the Linux kernel's Common
          Clock Framework [CCF] code in U-Boot's clock driver.
 
+config CLK_COMPOSITE_CCF
+       bool "Common Clock Framework [CCF] composite clk support "
+       depends on CLK_CCF
+       help
+         Enable this option if you want to (re-)use the Linux kernel's Common
+         Clock Framework [CCF] composite code in U-Boot's clock driver.
+
 config CLK_STM32F
        bool "Enable clock driver support for STM32F family"
        depends on CLK && (STM32F7 || STM32F4)
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0bc8f7e5ce..6c71b0fc16 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o
 obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
 obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o
 obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
+obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o
 
 obj-y += imx/
 obj-y += tegra/
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
new file mode 100644
index 0000000000..18adfd9850
--- /dev/null
+++ b/drivers/clk/clk-composite.c
@@ -0,0 +1,165 @@
+// 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 <linux/clk-provider.h>
+#include <clk.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_driver_data(clk->dev) : clk);
+       struct clk *mux = composite->mux;
+
+       return clk_mux_get_parent(mux);
+}
+
+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_driver_data(clk->dev) : clk);
+       const struct clk_ops *mux_ops = composite->mux_ops;
+       struct clk *mux = composite->mux;
+
+       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_driver_data(clk->dev) : clk);
+       const struct clk_ops *rate_ops = composite->rate_ops;
+       struct clk *rate = composite->rate;
+
+       return rate_ops->get_rate(rate);
+}
+
+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_driver_data(clk->dev) : clk);
+       const struct clk_ops *rate_ops = composite->rate_ops;
+       struct clk *clk_rate = composite->rate;
+
+       return rate_ops->set_rate(clk_rate, rate);
+}
+
+static int clk_composite_enable(struct clk *clk)
+{
+       struct clk_composite *composite = to_clk_composite(
+               clk_dev_binded(clk) ?
+               (struct clk *)dev_get_driver_data(clk->dev) : clk);
+       const struct clk_ops *gate_ops = composite->gate_ops;
+       struct clk *gate = composite->gate;
+
+       return gate_ops->enable(gate);
+}
+
+static int clk_composite_disable(struct clk *clk)
+{
+       struct clk_composite *composite = to_clk_composite(
+               clk_dev_binded(clk) ?
+               (struct clk *)dev_get_driver_data(clk->dev) : clk);
+       const struct clk_ops *gate_ops = composite->gate_ops;
+       struct clk *gate = composite->gate;
+
+       gate_ops->disable(gate);
+
+       return 0;
+}
+
+struct clk_ops clk_composite_ops = {
+       /* This will be set according to clk_register_composite */
+};
+
+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;
+       struct clk_ops *composite_ops = &clk_composite_ops;
+
+       composite = kzalloc(sizeof(*composite), GFP_KERNEL);
+       if (!composite)
+               return ERR_PTR(-ENOMEM);
+
+       if (mux && mux_ops) {
+               composite->mux = mux;
+               composite->mux_ops = mux_ops;
+               if (mux_ops->set_parent)
+                       composite_ops->set_parent = clk_composite_set_parent;
+               mux->data = (ulong)composite;
+       }
+
+       if (rate && rate_ops) {
+               if (!rate_ops->get_rate) {
+                       clk = ERR_PTR(-EINVAL);
+                       goto err;
+               }
+               composite_ops->get_rate = clk_composite_recalc_rate;
+
+               /* .set_rate requires either .round_rate or .determine_rate */
+               if (rate_ops->set_rate) {
+                               composite_ops->set_rate =
+                                               clk_composite_set_rate;
+               }
+
+               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;
+               composite_ops->enable = clk_composite_enable;
+               composite_ops->disable = clk_composite_disable;
+               gate->data = (ulong)composite;
+       }
+
+       clk = &composite->clk;
+       ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, (ulong)clk,
+                          name, parent_names[clk_composite_get_parent(clk)]);
+       if (ret) {
+               clk = ERR_PTR(ret);
+               goto err;
+       }
+
+       return clk;
+
+err:
+       kfree(composite);
+       return clk;
+}
+
+U_BOOT_DRIVER(clk_composite) = {
+       .name   = UBOOT_DM_CLK_COMPOSITE,
+       .id     = UCLASS_CLK,
+       .ops    = &clk_composite_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b2bed768b6..490713adb6 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -119,6 +119,28 @@ struct clk_fixed_rate {
 
 #define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_platdata(dev))
 
+struct clk_composite {
+       struct clk      clk;
+       struct clk_ops  ops;
+
+       struct clk      *mux;
+       struct clk      *rate;
+       struct clk      *gate;
+
+       const struct clk_ops    *mux_ops;
+       const struct clk_ops    *rate_ops;
+       const struct clk_ops    *gate_ops;
+};
+
+#define to_clk_composite(_clk) container_of(_clk, struct clk_composite, clk)
+
+struct clk *clk_register_composite(struct device *dev, const char *name,
+               const char * const *parent_names, int num_parents,
+               struct clk *mux_clk, const struct clk_ops *mux_ops,
+               struct clk *rate_clk, const struct clk_ops *rate_ops,
+               struct clk *gate_clk, const struct clk_ops *gate_ops,
+               unsigned long flags);
+
 int clk_register(struct clk *clk, const char *drv_name,
                 ulong drv_data, const char *name,
                 const char *parent_name);
-- 
2.16.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to