[PATCH] clk: let mxs specific clk-div clock type be a generic clock type

Thomas Abraham thomas.abraham at linaro.org
Sat Mar 16 08:50:01 EDT 2013


The mxs platform specific clk-div clock is an extended version of the
basic integer divider clock type that supports checking the stability
status of the divider clock output. This type of clock is found on
some of the Samsung platforms as well. So let the mxs specfic clk-div
clock type be a generic clock type that all platforms can utilize.

Cc: Shawn Guo <shawn.guo at linaro.org>
Cc: Mike Turquette <mturquette at linaro.org>
Signed-off-by: Thomas Abraham <thomas.abraham at linaro.org>
---
 drivers/clk/Makefile             |    1 +
 drivers/clk/clk-divider-status.c |  119 ++++++++++++++++++++++++++++++++++++++
 drivers/clk/mxs/Makefile         |    2 +-
 drivers/clk/mxs/clk-div.c        |  110 -----------------------------------
 drivers/clk/mxs/clk.h            |   12 +++-
 include/linux/clk-provider.h     |   21 +++++++
 6 files changed, 151 insertions(+), 114 deletions(-)
 create mode 100644 drivers/clk/clk-divider-status.c
 delete mode 100644 drivers/clk/mxs/clk-div.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0147022..0ac851a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-factor.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-fixed-rate.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-gate.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-mux.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-divider-status.o
 
 # SoCs specific
 obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o
diff --git a/drivers/clk/clk-divider-status.c b/drivers/clk/clk-divider-status.c
new file mode 100644
index 0000000..1d66059
--- /dev/null
+++ b/drivers/clk/clk-divider-status.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Extension to the adjustable divider clock implementation with support for
+ * divider clock stability checks.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+
+/*
+ * DOC: Adjustable divider clock with support for divider stability check
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.  clk->rate = parent->rate / divisor
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+static inline struct clk_divider_status *to_clk_div(struct clk_hw *hw)
+{
+	struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
+
+	return container_of(divider, struct clk_divider_status, divider);
+}
+
+static unsigned long clk_divider_status_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct clk_divider_status *div = to_clk_div(hw);
+
+	return div->ops->recalc_rate(&div->divider.hw, parent_rate);
+}
+
+static long clk_divider_status_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *prate)
+{
+	struct clk_divider_status *div = to_clk_div(hw);
+
+	return div->ops->round_rate(&div->divider.hw, rate, prate);
+}
+
+static int clk_divider_status_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_divider_status *div = to_clk_div(hw);
+	int ret;
+
+	ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
+	if (!ret) {
+		unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+		while (readl_relaxed(div->reg) & (1 << div->busy)) {
+			if (time_after(jiffies, timeout))
+				return -ETIMEDOUT;
+		}
+	}
+
+	return ret;
+}
+
+static struct clk_ops clk_divider_status_ops = {
+	.recalc_rate = clk_divider_status_recalc_rate,
+	.round_rate = clk_divider_status_round_rate,
+	.set_rate = clk_divider_status_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_status_ops);
+
+struct clk *clk_register_divider_status(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags, void __iomem *reg,
+		u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg_status, u8 shift_status, spinlock_t *lock)
+{
+	struct clk_divider_status *div;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div) {
+		pr_err("%s: could not allocate divider-status clk\n", __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	init.name = name;
+	init.ops = &clk_divider_status_ops;
+	init.flags = flags;
+	init.parent_names = (parent_name ? &parent_name : NULL);
+	init.num_parents = (parent_name ? 1 : 0);
+
+	div->reg = reg_status;
+	div->busy = shift_status;
+	div->ops = &clk_divider_ops;
+
+	div->divider.reg = reg;
+	div->divider.shift = shift;
+	div->divider.width = width;
+	div->divider.flags = clk_divider_flags;
+	div->divider.lock = lock;
+	div->divider.hw.init = &init;
+
+	clk = clk_register(NULL, &div->divider.hw);
+	if (IS_ERR(clk))
+		kfree(div);
+
+	return clk;
+}
diff --git a/drivers/clk/mxs/Makefile b/drivers/clk/mxs/Makefile
index a6a2223..8f8f1b3 100644
--- a/drivers/clk/mxs/Makefile
+++ b/drivers/clk/mxs/Makefile
@@ -2,7 +2,7 @@
 # Makefile for mxs specific clk
 #
 
-obj-y += clk.o clk-pll.o clk-ref.o clk-div.o clk-frac.o clk-ssp.o
+obj-y += clk.o clk-pll.o clk-ref.o clk-frac.o clk-ssp.o
 
 obj-$(CONFIG_SOC_IMX23) += clk-imx23.o
 obj-$(CONFIG_SOC_IMX28) += clk-imx28.o
diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c
deleted file mode 100644
index 90e1da9..0000000
--- a/drivers/clk/mxs/clk-div.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include "clk.h"
-
-/**
- * struct clk_div - mxs integer divider clock
- * @divider: the parent class
- * @ops: pointer to clk_ops of parent class
- * @reg: register address
- * @busy: busy bit shift
- *
- * The mxs divider clock is a subclass of basic clk_divider with an
- * addtional busy bit.
- */
-struct clk_div {
-	struct clk_divider divider;
-	const struct clk_ops *ops;
-	void __iomem *reg;
-	u8 busy;
-};
-
-static inline struct clk_div *to_clk_div(struct clk_hw *hw)
-{
-	struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
-
-	return container_of(divider, struct clk_div, divider);
-}
-
-static unsigned long clk_div_recalc_rate(struct clk_hw *hw,
-					 unsigned long parent_rate)
-{
-	struct clk_div *div = to_clk_div(hw);
-
-	return div->ops->recalc_rate(&div->divider.hw, parent_rate);
-}
-
-static long clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
-			       unsigned long *prate)
-{
-	struct clk_div *div = to_clk_div(hw);
-
-	return div->ops->round_rate(&div->divider.hw, rate, prate);
-}
-
-static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
-			    unsigned long parent_rate)
-{
-	struct clk_div *div = to_clk_div(hw);
-	int ret;
-
-	ret = div->ops->set_rate(&div->divider.hw, rate, parent_rate);
-	if (!ret)
-		ret = mxs_clk_wait(div->reg, div->busy);
-
-	return ret;
-}
-
-static struct clk_ops clk_div_ops = {
-	.recalc_rate = clk_div_recalc_rate,
-	.round_rate = clk_div_round_rate,
-	.set_rate = clk_div_set_rate,
-};
-
-struct clk *mxs_clk_div(const char *name, const char *parent_name,
-			void __iomem *reg, u8 shift, u8 width, u8 busy)
-{
-	struct clk_div *div;
-	struct clk *clk;
-	struct clk_init_data init;
-
-	div = kzalloc(sizeof(*div), GFP_KERNEL);
-	if (!div)
-		return ERR_PTR(-ENOMEM);
-
-	init.name = name;
-	init.ops = &clk_div_ops;
-	init.flags = CLK_SET_RATE_PARENT;
-	init.parent_names = (parent_name ? &parent_name: NULL);
-	init.num_parents = (parent_name ? 1 : 0);
-
-	div->reg = reg;
-	div->busy = busy;
-
-	div->divider.reg = reg;
-	div->divider.shift = shift;
-	div->divider.width = width;
-	div->divider.flags = CLK_DIVIDER_ONE_BASED;
-	div->divider.lock = &mxs_lock;
-	div->divider.hw.init = &init;
-	div->ops = &clk_divider_ops;
-
-	clk = clk_register(NULL, &div->divider.hw);
-	if (IS_ERR(clk))
-		kfree(div);
-
-	return clk;
-}
diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h
index 81421e2..865f495 100644
--- a/drivers/clk/mxs/clk.h
+++ b/drivers/clk/mxs/clk.h
@@ -29,9 +29,6 @@ struct clk *mxs_clk_pll(const char *name, const char *parent_name,
 struct clk *mxs_clk_ref(const char *name, const char *parent_name,
 			void __iomem *reg, u8 idx);
 
-struct clk *mxs_clk_div(const char *name, const char *parent_name,
-			void __iomem *reg, u8 shift, u8 width, u8 busy);
-
 struct clk *mxs_clk_frac(const char *name, const char *parent_name,
 			 void __iomem *reg, u8 shift, u8 width, u8 busy);
 
@@ -63,4 +60,13 @@ static inline struct clk *mxs_clk_fixed_factor(const char *name,
 					 CLK_SET_RATE_PARENT, mult, div);
 }
 
+static inline struct clk *mxs_clk_div(const char *name,
+			const char *parent_name, void __iomem *reg, u8 shift,
+			u8 width, u8 busy)
+{
+	return clk_register_divider_status(NULL, name, parent_name,
+				CLK_SET_RATE_PARENT, reg, shift, width,
+				CLK_DIVIDER_ONE_BASED, reg, busy, &mxs_lock);
+}
+
 #endif /* __MXS_CLK_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7f197d7..6309335 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -268,6 +268,27 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		spinlock_t *lock);
 
 /**
+ * struct clk_divider_status - integer divider clock with additional status bit
+ * @divider: the parent class
+ * @ops: pointer to clk_ops of parent class
+ * @reg: register containing the divider status bit
+ * @busy: divider busy bit shift
+ *
+ * This clock is a subclass of basic clk_divider with an addtional busy bit.
+ */
+struct clk_divider_status {
+	struct clk_divider divider;
+	const struct clk_ops *ops;
+	void __iomem *reg;
+	u8 busy;
+};
+
+struct clk *clk_register_divider_status(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags, void __iomem *reg,
+		u8 shift, u8 width, u8 clk_divider_flags,
+		void __iomem *reg_status, u8 shift_status, spinlock_t *lock);
+
+/**
  * struct clk_mux - multiplexer clock
  *
  * @hw:		handle between common and hardware-specific interfaces
-- 
1.7.5.4




More information about the linux-arm-kernel mailing list