@@ -110,4 +110,8 @@ config IMX_CLK_PLLV2
bool
depends on GENERIC_CLK
+config IMX_CLK_GATE2B
+ bool
+ depends on GENERIC_CLK
+
endif
@@ -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
new file mode 100644
@@ -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);
@@ -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__ */