[PATCH 07/12] clk: mmp: add clock type composite for mix

Chao Xie chao.xie at marvell.com
Mon Jun 9 18:27:43 PDT 2014


From: Chao Xie <chao.xie at marvell.com>

The general composite clock supports div/mux/gate.
marvell SOCes have many clocks that need change
div and mux together. So it need the composite
clock that supports mix/gate.

Signed-off-by: Chao Xie <chao.xie at marvell.com>
---
 drivers/clk/mmp/Makefile            |   3 +-
 drivers/clk/mmp/clk-mix-composite.c | 195 ++++++++++++++++++++++++++++++++++++
 drivers/clk/mmp/clk.h               |  20 ++++
 3 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/mmp/clk-mix-composite.c

diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 2855f7b..2cd7d94 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -2,7 +2,8 @@
 # Makefile for mmp specific clk
 #
 
-obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o	\
+	 clk-mix-composite.o
 
 obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
 obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-mix-composite.c b/drivers/clk/mmp/clk-mix-composite.c
new file mode 100644
index 0000000..79d5286
--- /dev/null
+++ b/drivers/clk/mmp/clk-mix-composite.c
@@ -0,0 +1,195 @@
+/*
+ * mmp mix(div and mux) clock operation source file
+ *
+ * Copyright (C) 2014 Marvell
+ * Chao Xie <chao.xie at marvell.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define to_clk_composite(_hw) container_of(_hw, struct mmp_clk_composite, hw)
+
+static u8 mmp_clk_composite_get_parent(struct clk_hw *hw)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->get_parent(mix_hw);
+}
+
+static int mmp_clk_composite_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->set_parent(mix_hw, index);
+}
+
+static int mmp_clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->set_rate(mix_hw, rate, parent_rate);
+}
+
+static unsigned long mmp_clk_composite_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->recalc_rate(mix_hw, parent_rate);
+}
+
+static long mmp_clk_composite_determine_rate(struct clk_hw *hw,
+					unsigned long rate,
+					unsigned long *best_parent_rate,
+					struct clk **best_parent_p)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->determine_rate(mix_hw, rate, best_parent_rate,
+					best_parent_p);
+}
+
+static int mmp_clk_composite_set_rate_and_parent(struct clk_hw *hw,
+					unsigned long rate,
+					unsigned long parent_rate, u8 index)
+
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+
+	return mix_ops->set_rate_and_parent(mix_hw, rate, parent_rate, index);
+}
+
+static int mmp_clk_composite_is_enabled(struct clk_hw *hw)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *gate_ops = composite->gate_ops;
+	struct clk_hw *gate_hw = composite->gate_hw;
+
+	gate_hw->clk = hw->clk;
+
+	return gate_ops->is_enabled(gate_hw);
+}
+
+static int mmp_clk_composite_enable(struct clk_hw *hw)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *gate_ops = composite->gate_ops;
+	struct clk_hw *gate_hw = composite->gate_hw;
+
+	gate_hw->clk = hw->clk;
+
+	return gate_ops->enable(gate_hw);
+}
+
+static void mmp_clk_composite_disable(struct clk_hw *hw)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *gate_ops = composite->gate_ops;
+	struct clk_hw *gate_hw = composite->gate_hw;
+
+	gate_hw->clk = hw->clk;
+
+	gate_ops->disable(gate_hw);
+}
+
+static void mmp_clk_composite_init(struct clk_hw *hw)
+{
+	struct mmp_clk_composite *composite = to_clk_composite(hw);
+	const struct clk_ops *gate_ops = composite->gate_ops;
+	struct clk_hw *gate_hw = composite->gate_hw;
+	const struct clk_ops *mix_ops = composite->mix_ops;
+	struct clk_hw *mix_hw = composite->mix_hw;
+
+	mix_hw->clk = hw->clk;
+	gate_hw->clk = hw->clk;
+
+	if (mix_ops->init)
+		mix_ops->init(mix_hw);
+	if (gate_ops->init)
+		gate_ops->init(gate_hw);
+}
+
+static struct clk_ops mmp_clk_composite_ops = {
+	.enable = mmp_clk_composite_enable,
+	.disable = mmp_clk_composite_disable,
+	.is_enabled = mmp_clk_composite_is_enabled,
+	.determine_rate = mmp_clk_composite_determine_rate,
+	.set_rate_and_parent = mmp_clk_composite_set_rate_and_parent,
+	.set_rate = mmp_clk_composite_set_rate,
+	.recalc_rate = mmp_clk_composite_recalc_rate,
+	.get_parent = mmp_clk_composite_get_parent,
+	.set_parent = mmp_clk_composite_set_parent,
+	.init = mmp_clk_composite_init,
+};
+
+struct clk *mmp_clk_register_composite(struct device *dev, const char *name,
+			const char **parent_names, int num_parents,
+			struct clk_hw *mix_hw, const struct clk_ops *mix_ops,
+			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+			unsigned long flags)
+{
+	struct clk *clk;
+	struct clk_init_data init;
+	struct mmp_clk_composite *composite;
+
+	if (!mix_hw || !gate_hw)
+		return ERR_PTR(-EINVAL);
+
+	composite = kzalloc(sizeof(*composite), GFP_KERNEL);
+	if (!composite) {
+		pr_err("%s: could not allocate mmp composite clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = name;
+	init.flags = flags;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.ops = &mmp_clk_composite_ops;
+
+	composite->mix_hw = mix_hw;
+	composite->mix_ops = mix_ops;
+	composite->gate_hw = gate_hw;
+	composite->gate_ops = gate_ops;
+	composite->hw.init = &init;
+
+	clk = clk_register(dev, &composite->hw);
+	if (IS_ERR(clk))
+		kfree(composite);
+
+	return clk;
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 9096f0a..9827a4f 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -120,6 +120,26 @@ extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
 			spinlock_t *lock);
 
 
+/* Clock type "composite" for mix clock */
+struct mmp_clk_composite {
+	struct clk_hw hw;
+	struct clk_ops ops;
+
+	struct clk_hw *mix_hw;
+	struct clk_hw *gate_hw;
+
+	const struct clk_ops *mix_ops;
+	const struct clk_ops *gate_ops;
+};
+
+extern struct clk *mmp_clk_register_composite(struct device *dev,
+			const char *name,
+			const char **parent_names, int num_parents,
+			struct clk_hw *mix_hw, const struct clk_ops *mix_ops,
+			struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+			unsigned long flags);
+
+
 extern struct clk *mmp_clk_register_pll2(const char *name,
 		const char *parent_name, unsigned long flags);
 extern struct clk *mmp_clk_register_apbc(const char *name,
-- 
1.8.3.2




More information about the linux-arm-kernel mailing list