diff mbox

[RFC,V2,5/8] ARM i.MX: clk: add generic support of gate2b

Message ID 1323912295-21144-5-git-send-email-richard.zhao@freescale.com
State RFC
Headers show

Commit Message

Richard Zhao Dec. 15, 2011, 1:24 a.m. UTC
From: Richard Zhao <richard.zhao@linaro.org>

gate with two control bits is found in imx5/6 CCGR registers.

Signed-off-by: Richard Zhao <richard.zhao@linaro.org>
---
 arch/arm/plat-mxc/Kconfig              |    4 ++
 arch/arm/plat-mxc/Makefile             |    1 +
 arch/arm/plat-mxc/clk-gate2b.c         |   88 ++++++++++++++++++++++++++++++++
 arch/arm/plat-mxc/include/mach/clock.h |   22 ++++++++
 4 files changed, 115 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-mxc/clk-gate2b.c
diff mbox

Patch

diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index 903c15e..0f27f05 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -110,4 +110,8 @@  config IMX_CLK_PLLV2
 	bool
 	depends on GENERIC_CLK
 
+config IMX_CLK_GATE2B
+	bool
+	depends on GENERIC_CLK
+
 endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 96d45dc..0689e78 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -7,6 +7,7 @@  obj-y := clock.o time.o devices.o cpu.o system.o irq-common.o
 
 obj-$(CONFIG_ARM_GIC) += gic.o
 obj-$(CONFIG_IMX_CLK_PLLV2) += clk-pllv2.o
+obj-$(CONFIG_IMX_CLK_GATE2B) += clk-gate2b.o
 obj-$(CONFIG_MXC_TZIC) += tzic.o
 obj-$(CONFIG_MXC_AVIC) += avic.o
 
diff --git a/arch/arm/plat-mxc/clk-gate2b.c b/arch/arm/plat-mxc/clk-gate2b.c
new file mode 100644
index 0000000..f406508
--- /dev/null
+++ b/arch/arm/plat-mxc/clk-gate2b.c
@@ -0,0 +1,88 @@ 
+/*
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <mach/clock.h>
+
+#define to_clk_gate2b(ck) container_of(ck, struct clk_gate2b, clk)
+
+static int clk_gate2b_enable(struct clk *clk)
+{
+	struct clk_gate2b *gate2b = to_clk_gate2b(clk);
+	unsigned long flags;
+	u32 reg;
+
+	if (gate2b->lock)
+		spin_lock_irqsave(gate2b->lock, flags);
+
+	reg = __raw_readl(gate2b->reg);
+	reg &= ~(0x3 << gate2b->shift);
+	reg |= gate2b->val_en << gate2b->shift;
+	__raw_writel(reg, gate2b->reg);
+
+	if (gate2b->lock)
+		spin_unlock_irqrestore(gate2b->lock, flags);
+
+	return 0;
+}
+
+static void clk_gate2b_disable(struct clk *clk)
+{
+	struct clk_gate2b *gate2b = to_clk_gate2b(clk);
+	unsigned long flags;
+	u32 reg;
+
+	if (gate2b->lock)
+		spin_lock_irqsave(gate2b->lock, flags);
+
+	reg = __raw_readl(gate2b->reg);
+	reg &= ~(0x3 << gate2b->shift);
+	reg |= gate2b->val_dis << gate2b->shift;
+	__raw_writel(reg, gate2b->reg);
+
+	if (gate2b->lock)
+		spin_unlock_irqrestore(gate2b->lock, flags);
+
+}
+
+struct clk_hw_ops clk_gate2b_ops = {
+	.enable = clk_gate2b_enable,
+	.disable = clk_gate2b_disable,
+};
+EXPORT_SYMBOL_GPL(clk_gate2b_ops);
+
+int clk_gate2b_set_val(struct clk *clk, int en, int dis)
+{
+	struct clk_gate2b *gate2b = to_clk_gate2b(clk);
+	unsigned long flags;
+	u32 reg, val;
+
+	en &= 0x3;
+	dis &= 0x3;
+
+	if (gate2b->lock)
+		spin_lock_irqsave(gate2b->lock, flags);
+
+	reg = __raw_readl(gate2b->reg);
+	val = (reg >> gate2b->shift) & 0x3;
+	reg &= ~(0x3 << gate2b->shift);
+	if (val == gate2b->val_en && val != en)
+		reg |= en << gate2b->shift;
+	else if (val == gate2b->val_dis && val != dis)
+		reg |= dis << gate2b->shift;
+	__raw_writel(reg, gate2b->reg);
+	gate2b->val_en = en;
+	gate2b->val_dis = dis;
+
+	if (gate2b->lock)
+		spin_unlock_irqrestore(gate2b->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate2b_set_val);
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h
index 2eb11c7..f62256e 100644
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ b/arch/arm/plat-mxc/include/mach/clock.h
@@ -87,6 +87,28 @@  extern struct clk_hw_ops clk_pllv2_ops;
 		.base = (_base), \
 	}
 
+/**
+ * gate with 2 control bits
+ *
+ * @parent	the parent clk
+ * @reg		the register address
+ * @shift	control bits offset
+ * @en_val	value when clk enabled
+ * @dis_val	value when clk disabled
+ */
+struct clk_gate2b {
+	struct clk	clk;
+	void __iomem	*reg;
+	u8		shift;
+	u8		val_en:2;
+	u8		val_dis:2;
+	spinlock_t	*lock;
+};
+
+extern struct clk_hw_ops clk_gate2b_ops;
+
+int clk_gate2b_set_val(struct clk *clk, int en, int dis);
+
 #endif /* CONFIG_GENERIC_CLK */
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_ARCH_MXC_CLOCK_H__ */