clk: imx: add imx7ulp composite clk support
authorA.s. Dong <aisheng.dong@nxp.com>
Wed, 14 Nov 2018 13:01:51 +0000 (13:01 +0000)
committerStephen Boyd <sboyd@kernel.org>
Mon, 3 Dec 2018 19:31:36 +0000 (11:31 -0800)
The imx composite clk is designed for Peripheral Clock Control (PCC)
module observed in IMX ULP SoC series.

NOTE pcc can only be operated when clk is gated.

Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Anson Huang <Anson.Huang@nxp.com>
Cc: Bai Ping <ping.bai@nxp.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
[sboyd@kernel.org: Include clk.h for sparse warnings]
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/imx/Makefile
drivers/clk/imx/clk-composite-7ulp.c [new file with mode: 0644]
drivers/clk/imx/clk.h

index e7248de..a5cab3e 100644 (file)
@@ -4,6 +4,7 @@ obj-y += \
        clk.o \
        clk-busy.o \
        clk-cpu.o \
+       clk-composite-7ulp.o \
        clk-divider-gate.o \
        clk-fixup-div.o \
        clk-fixup-mux.o \
diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c
new file mode 100644 (file)
index 0000000..060f860
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017~2018 NXP
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define PCG_PCS_SHIFT  24
+#define PCG_PCS_MASK   0x7
+#define PCG_CGC_SHIFT  30
+#define PCG_FRAC_SHIFT 3
+#define PCG_FRAC_WIDTH 1
+#define PCG_FRAC_MASK  BIT(3)
+#define PCG_PCD_SHIFT  0
+#define PCG_PCD_WIDTH  3
+#define PCG_PCD_MASK   0x7
+
+struct clk_hw *imx7ulp_clk_composite(const char *name,
+                                    const char * const *parent_names,
+                                    int num_parents, bool mux_present,
+                                    bool rate_present, bool gate_present,
+                                    void __iomem *reg)
+{
+       struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
+       struct clk_fractional_divider *fd = NULL;
+       struct clk_gate *gate = NULL;
+       struct clk_mux *mux = NULL;
+       struct clk_hw *hw;
+
+       if (mux_present) {
+               mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+               if (!mux)
+                       return ERR_PTR(-ENOMEM);
+               mux_hw = &mux->hw;
+               mux->reg = reg;
+               mux->shift = PCG_PCS_SHIFT;
+               mux->mask = PCG_PCS_MASK;
+       }
+
+       if (rate_present) {
+               fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+               if (!fd) {
+                       kfree(mux);
+                       return ERR_PTR(-ENOMEM);
+               }
+               fd_hw = &fd->hw;
+               fd->reg = reg;
+               fd->mshift = PCG_FRAC_SHIFT;
+               fd->mwidth = PCG_FRAC_WIDTH;
+               fd->mmask  = PCG_FRAC_MASK;
+               fd->nshift = PCG_PCD_SHIFT;
+               fd->nwidth = PCG_PCD_WIDTH;
+               fd->nmask = PCG_PCD_MASK;
+               fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+       }
+
+       if (gate_present) {
+               gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+               if (!gate) {
+                       kfree(mux);
+                       kfree(fd);
+                       return ERR_PTR(-ENOMEM);
+               }
+               gate_hw = &gate->hw;
+               gate->reg = reg;
+               gate->bit_idx = PCG_CGC_SHIFT;
+       }
+
+       hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
+                                      mux_hw, &clk_mux_ops, fd_hw,
+                                      &clk_fractional_divider_ops, gate_hw,
+                                      &clk_gate_ops, CLK_SET_RATE_GATE |
+                                      CLK_SET_PARENT_GATE);
+       if (IS_ERR(hw)) {
+               kfree(mux);
+               kfree(fd);
+               kfree(gate);
+       }
+
+       return hw;
+}
index 153d9a4..ece7097 100644 (file)
@@ -71,6 +71,12 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
                             u8 width, void __iomem *busy_reg, u8 busy_shift,
                             const char **parent_names, int num_parents);
 
+struct clk_hw *imx7ulp_clk_composite(const char *name,
+                                    const char * const *parent_names,
+                                    int num_parents, bool mux_present,
+                                    bool rate_present, bool gate_present,
+                                    void __iomem *reg);
+
 struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
                                  void __iomem *reg, u8 shift, u8 width,
                                  void (*fixup)(u32 *val));