Commit | Line | Data |
---|---|---|
b75c0151 SH |
1 | /* |
2 | * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> | |
3 | * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Gated clock implementation | |
10 | */ | |
11 | ||
12 | #include <linux/clk-provider.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/string.h> | |
d7b8c030 | 18 | #include "clk.h" |
b75c0151 SH |
19 | |
20 | /** | |
21 | * DOC: basic gatable clock which can gate and ungate it's ouput | |
22 | * | |
23 | * Traits of this clock: | |
24 | * prepare - clk_(un)prepare only ensures parent is (un)prepared | |
25 | * enable - clk_enable and clk_disable are functional & control gating | |
26 | * rate - inherits rate from parent. No clk_set_rate support | |
27 | * parent - fixed parent. No clk_set_parent support | |
28 | */ | |
29 | ||
54ee1471 SG |
30 | struct clk_gate2 { |
31 | struct clk_hw hw; | |
32 | void __iomem *reg; | |
33 | u8 bit_idx; | |
45682922 | 34 | u8 cgr_val; |
54ee1471 SG |
35 | u8 flags; |
36 | spinlock_t *lock; | |
f9f28cdf | 37 | unsigned int *share_count; |
54ee1471 SG |
38 | }; |
39 | ||
40 | #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) | |
b75c0151 SH |
41 | |
42 | static int clk_gate2_enable(struct clk_hw *hw) | |
43 | { | |
54ee1471 | 44 | struct clk_gate2 *gate = to_clk_gate2(hw); |
b75c0151 SH |
45 | u32 reg; |
46 | unsigned long flags = 0; | |
47 | ||
94b5c028 | 48 | spin_lock_irqsave(gate->lock, flags); |
b75c0151 | 49 | |
f9f28cdf SG |
50 | if (gate->share_count && (*gate->share_count)++ > 0) |
51 | goto out; | |
52 | ||
b75c0151 | 53 | reg = readl(gate->reg); |
45682922 SA |
54 | reg &= ~(3 << gate->bit_idx); |
55 | reg |= gate->cgr_val << gate->bit_idx; | |
b75c0151 SH |
56 | writel(reg, gate->reg); |
57 | ||
f9f28cdf | 58 | out: |
94b5c028 | 59 | spin_unlock_irqrestore(gate->lock, flags); |
b75c0151 SH |
60 | |
61 | return 0; | |
62 | } | |
63 | ||
64 | static void clk_gate2_disable(struct clk_hw *hw) | |
65 | { | |
54ee1471 | 66 | struct clk_gate2 *gate = to_clk_gate2(hw); |
b75c0151 SH |
67 | u32 reg; |
68 | unsigned long flags = 0; | |
69 | ||
94b5c028 | 70 | spin_lock_irqsave(gate->lock, flags); |
b75c0151 | 71 | |
63288b72 SG |
72 | if (gate->share_count) { |
73 | if (WARN_ON(*gate->share_count == 0)) | |
74 | goto out; | |
75 | else if (--(*gate->share_count) > 0) | |
76 | goto out; | |
77 | } | |
f9f28cdf | 78 | |
b75c0151 SH |
79 | reg = readl(gate->reg); |
80 | reg &= ~(3 << gate->bit_idx); | |
81 | writel(reg, gate->reg); | |
82 | ||
f9f28cdf | 83 | out: |
94b5c028 | 84 | spin_unlock_irqrestore(gate->lock, flags); |
b75c0151 SH |
85 | } |
86 | ||
63288b72 | 87 | static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx) |
b75c0151 | 88 | { |
63288b72 | 89 | u32 val = readl(reg); |
b75c0151 | 90 | |
63288b72 | 91 | if (((val >> bit_idx) & 1) == 1) |
b75c0151 SH |
92 | return 1; |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
63288b72 SG |
97 | static int clk_gate2_is_enabled(struct clk_hw *hw) |
98 | { | |
99 | struct clk_gate2 *gate = to_clk_gate2(hw); | |
100 | ||
3d27bc5c AH |
101 | return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); |
102 | } | |
103 | ||
104 | static void clk_gate2_disable_unused(struct clk_hw *hw) | |
105 | { | |
106 | struct clk_gate2 *gate = to_clk_gate2(hw); | |
107 | unsigned long flags = 0; | |
108 | u32 reg; | |
109 | ||
110 | spin_lock_irqsave(gate->lock, flags); | |
111 | ||
112 | if (!gate->share_count || *gate->share_count == 0) { | |
113 | reg = readl(gate->reg); | |
114 | reg &= ~(3 << gate->bit_idx); | |
115 | writel(reg, gate->reg); | |
116 | } | |
117 | ||
118 | spin_unlock_irqrestore(gate->lock, flags); | |
63288b72 SG |
119 | } |
120 | ||
b75c0151 SH |
121 | static struct clk_ops clk_gate2_ops = { |
122 | .enable = clk_gate2_enable, | |
123 | .disable = clk_gate2_disable, | |
3d27bc5c | 124 | .disable_unused = clk_gate2_disable_unused, |
b75c0151 SH |
125 | .is_enabled = clk_gate2_is_enabled, |
126 | }; | |
127 | ||
128 | struct clk *clk_register_gate2(struct device *dev, const char *name, | |
129 | const char *parent_name, unsigned long flags, | |
45682922 | 130 | void __iomem *reg, u8 bit_idx, u8 cgr_val, |
f9f28cdf SG |
131 | u8 clk_gate2_flags, spinlock_t *lock, |
132 | unsigned int *share_count) | |
b75c0151 | 133 | { |
54ee1471 | 134 | struct clk_gate2 *gate; |
b75c0151 SH |
135 | struct clk *clk; |
136 | struct clk_init_data init; | |
137 | ||
54ee1471 | 138 | gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL); |
b75c0151 SH |
139 | if (!gate) |
140 | return ERR_PTR(-ENOMEM); | |
141 | ||
54ee1471 | 142 | /* struct clk_gate2 assignments */ |
b75c0151 SH |
143 | gate->reg = reg; |
144 | gate->bit_idx = bit_idx; | |
45682922 | 145 | gate->cgr_val = cgr_val; |
b75c0151 SH |
146 | gate->flags = clk_gate2_flags; |
147 | gate->lock = lock; | |
f9f28cdf | 148 | gate->share_count = share_count; |
b75c0151 SH |
149 | |
150 | init.name = name; | |
151 | init.ops = &clk_gate2_ops; | |
152 | init.flags = flags; | |
153 | init.parent_names = parent_name ? &parent_name : NULL; | |
154 | init.num_parents = parent_name ? 1 : 0; | |
155 | ||
156 | gate->hw.init = &init; | |
157 | ||
158 | clk = clk_register(dev, &gate->hw); | |
159 | if (IS_ERR(clk)) | |
ecf026dc | 160 | kfree(gate); |
b75c0151 SH |
161 | |
162 | return clk; | |
163 | } |