Commit | Line | Data |
---|---|---|
cdce3546 CX |
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 | ||
27 | static int mmp_clk_gate_enable(struct clk_hw *hw) | |
28 | { | |
29 | struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); | |
cdce3546 CX |
30 | unsigned long flags = 0; |
31 | unsigned long rate; | |
32 | u32 tmp; | |
33 | ||
34 | if (gate->lock) | |
35 | spin_lock_irqsave(gate->lock, flags); | |
36 | ||
37 | tmp = readl(gate->reg); | |
38 | tmp &= ~gate->mask; | |
39 | tmp |= gate->val_enable; | |
40 | writel(tmp, gate->reg); | |
41 | ||
42 | if (gate->lock) | |
43 | spin_unlock_irqrestore(gate->lock, flags); | |
44 | ||
45 | if (gate->flags & MMP_CLK_GATE_NEED_DELAY) { | |
aef28cb6 | 46 | rate = clk_hw_get_rate(hw); |
cdce3546 CX |
47 | /* Need delay 2 cycles. */ |
48 | udelay(2000000/rate); | |
49 | } | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
54 | static void mmp_clk_gate_disable(struct clk_hw *hw) | |
55 | { | |
56 | struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); | |
57 | unsigned long flags = 0; | |
58 | u32 tmp; | |
59 | ||
60 | if (gate->lock) | |
61 | spin_lock_irqsave(gate->lock, flags); | |
62 | ||
63 | tmp = readl(gate->reg); | |
64 | tmp &= ~gate->mask; | |
65 | tmp |= gate->val_disable; | |
66 | writel(tmp, gate->reg); | |
67 | ||
68 | if (gate->lock) | |
69 | spin_unlock_irqrestore(gate->lock, flags); | |
70 | } | |
71 | ||
72 | static int mmp_clk_gate_is_enabled(struct clk_hw *hw) | |
73 | { | |
74 | struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); | |
75 | unsigned long flags = 0; | |
76 | u32 tmp; | |
77 | ||
78 | if (gate->lock) | |
79 | spin_lock_irqsave(gate->lock, flags); | |
80 | ||
81 | tmp = readl(gate->reg); | |
82 | ||
83 | if (gate->lock) | |
84 | spin_unlock_irqrestore(gate->lock, flags); | |
85 | ||
86 | return (tmp & gate->mask) == gate->val_enable; | |
87 | } | |
88 | ||
89 | const struct clk_ops mmp_clk_gate_ops = { | |
90 | .enable = mmp_clk_gate_enable, | |
91 | .disable = mmp_clk_gate_disable, | |
92 | .is_enabled = mmp_clk_gate_is_enabled, | |
93 | }; | |
94 | ||
95 | struct clk *mmp_clk_register_gate(struct device *dev, const char *name, | |
96 | const char *parent_name, unsigned long flags, | |
97 | void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable, | |
98 | unsigned int gate_flags, spinlock_t *lock) | |
99 | { | |
100 | struct mmp_clk_gate *gate; | |
101 | struct clk *clk; | |
102 | struct clk_init_data init; | |
103 | ||
104 | /* allocate the gate */ | |
105 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | |
106 | if (!gate) { | |
107 | pr_err("%s:%s could not allocate gate clk\n", __func__, name); | |
108 | return ERR_PTR(-ENOMEM); | |
109 | } | |
110 | ||
111 | init.name = name; | |
112 | init.ops = &mmp_clk_gate_ops; | |
113 | init.flags = flags | CLK_IS_BASIC; | |
114 | init.parent_names = (parent_name ? &parent_name : NULL); | |
115 | init.num_parents = (parent_name ? 1 : 0); | |
116 | ||
117 | /* struct clk_gate assignments */ | |
118 | gate->reg = reg; | |
119 | gate->mask = mask; | |
120 | gate->val_enable = val_enable; | |
121 | gate->val_disable = val_disable; | |
122 | gate->flags = gate_flags; | |
123 | gate->lock = lock; | |
124 | gate->hw.init = &init; | |
125 | ||
126 | clk = clk_register(dev, &gate->hw); | |
127 | ||
128 | if (IS_ERR(clk)) | |
129 | kfree(gate); | |
130 | ||
131 | return clk; | |
132 | } |