aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorChao Xie <chao.xie@marvell.com>2014-10-30 22:13:46 -0400
committerMichael Turquette <mturquette@linaro.org>2014-11-12 19:34:00 -0500
commitcdce35460f5bd929cbcb75a8f436776bd0112f49 (patch)
tree00f8559dd38991327e643c86701c83faf5ceff4c /drivers/clk
parentee81f4ee2a3632a2d7928f680c4af8243a18762f (diff)
clk: mmp: add mmp private gate clock
Some SOCes have this kind of the gate clock 1. There are some bits to control the gate not only one bit. 2. It is not always that "1" is to enable while "0" is to disable when write register. So we have to define the "mask", "enable_val", "disable_val" for this kind of gate clock. Signed-off-by: Chao Xie <chao.xie@marvell.com> Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> Signed-off-by: Michael Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/mmp/Makefile2
-rw-r--r--drivers/clk/mmp/clk-gate.c133
-rw-r--r--drivers/clk/mmp/clk.h21
3 files changed, 155 insertions, 1 deletions
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
index 8bfee8605949..2855f7b686ed 100644
--- a/drivers/clk/mmp/Makefile
+++ b/drivers/clk/mmp/Makefile
@@ -2,7 +2,7 @@
2# Makefile for mmp specific clk 2# Makefile for mmp specific clk
3# 3#
4 4
5obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o 5obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o
6 6
7obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o 7obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
8obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o 8obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c
new file mode 100644
index 000000000000..adbd9d64ded2
--- /dev/null
+++ b/drivers/clk/mmp/clk-gate.c
@@ -0,0 +1,133 @@
1/*
2 * mmp gate clock operation source file
3 *
4 * Copyright (C) 2014 Marvell
5 * Chao Xie <chao.xie@marvell.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include <linux/clk-provider.h>
13#include <linux/slab.h>
14#include <linux/io.h>
15#include <linux/err.h>
16#include <linux/delay.h>
17
18#include "clk.h"
19
20/*
21 * Some clocks will have mutiple bits to enable the clocks, and
22 * the bits to disable the clock is not same as enabling bits.
23 */
24
25#define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw)
26
27static int mmp_clk_gate_enable(struct clk_hw *hw)
28{
29 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
30 struct clk *clk = hw->clk;
31 unsigned long flags = 0;
32 unsigned long rate;
33 u32 tmp;
34
35 if (gate->lock)
36 spin_lock_irqsave(gate->lock, flags);
37
38 tmp = readl(gate->reg);
39 tmp &= ~gate->mask;
40 tmp |= gate->val_enable;
41 writel(tmp, gate->reg);
42
43 if (gate->lock)
44 spin_unlock_irqrestore(gate->lock, flags);
45
46 if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
47 rate = __clk_get_rate(clk);
48 /* Need delay 2 cycles. */
49 udelay(2000000/rate);
50 }
51
52 return 0;
53}
54
55static void mmp_clk_gate_disable(struct clk_hw *hw)
56{
57 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
58 unsigned long flags = 0;
59 u32 tmp;
60
61 if (gate->lock)
62 spin_lock_irqsave(gate->lock, flags);
63
64 tmp = readl(gate->reg);
65 tmp &= ~gate->mask;
66 tmp |= gate->val_disable;
67 writel(tmp, gate->reg);
68
69 if (gate->lock)
70 spin_unlock_irqrestore(gate->lock, flags);
71}
72
73static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
74{
75 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
76 unsigned long flags = 0;
77 u32 tmp;
78
79 if (gate->lock)
80 spin_lock_irqsave(gate->lock, flags);
81
82 tmp = readl(gate->reg);
83
84 if (gate->lock)
85 spin_unlock_irqrestore(gate->lock, flags);
86
87 return (tmp & gate->mask) == gate->val_enable;
88}
89
90const struct clk_ops mmp_clk_gate_ops = {
91 .enable = mmp_clk_gate_enable,
92 .disable = mmp_clk_gate_disable,
93 .is_enabled = mmp_clk_gate_is_enabled,
94};
95
96struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
97 const char *parent_name, unsigned long flags,
98 void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
99 unsigned int gate_flags, spinlock_t *lock)
100{
101 struct mmp_clk_gate *gate;
102 struct clk *clk;
103 struct clk_init_data init;
104
105 /* allocate the gate */
106 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
107 if (!gate) {
108 pr_err("%s:%s could not allocate gate clk\n", __func__, name);
109 return ERR_PTR(-ENOMEM);
110 }
111
112 init.name = name;
113 init.ops = &mmp_clk_gate_ops;
114 init.flags = flags | CLK_IS_BASIC;
115 init.parent_names = (parent_name ? &parent_name : NULL);
116 init.num_parents = (parent_name ? 1 : 0);
117
118 /* struct clk_gate assignments */
119 gate->reg = reg;
120 gate->mask = mask;
121 gate->val_enable = val_enable;
122 gate->val_disable = val_disable;
123 gate->flags = gate_flags;
124 gate->lock = lock;
125 gate->hw.init = &init;
126
127 clk = clk_register(dev, &gate->hw);
128
129 if (IS_ERR(clk))
130 kfree(gate);
131
132 return clk;
133}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
index 26b24699ccd7..23371062072b 100644
--- a/drivers/clk/mmp/clk.h
+++ b/drivers/clk/mmp/clk.h
@@ -103,6 +103,27 @@ extern struct clk *mmp_clk_register_mix(struct device *dev,
103 spinlock_t *lock); 103 spinlock_t *lock);
104 104
105 105
106/* Clock type "gate". MMP private gate */
107#define MMP_CLK_GATE_NEED_DELAY BIT(0)
108
109struct mmp_clk_gate {
110 struct clk_hw hw;
111 void __iomem *reg;
112 u32 mask;
113 u32 val_enable;
114 u32 val_disable;
115 unsigned int flags;
116 spinlock_t *lock;
117};
118
119extern const struct clk_ops mmp_clk_gate_ops;
120extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
121 const char *parent_name, unsigned long flags,
122 void __iomem *reg, u32 mask, u32 val_enable,
123 u32 val_disable, unsigned int gate_flags,
124 spinlock_t *lock);
125
126
106extern struct clk *mmp_clk_register_pll2(const char *name, 127extern struct clk *mmp_clk_register_pll2(const char *name,
107 const char *parent_name, unsigned long flags); 128 const char *parent_name, unsigned long flags);
108extern struct clk *mmp_clk_register_apbc(const char *name, 129extern struct clk *mmp_clk_register_apbc(const char *name,