diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2013-01-11 02:46:20 -0500 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2013-01-28 13:19:07 -0500 |
commit | 8f8f484bf355e546c62c47b8a8c8d19b28787798 (patch) | |
tree | cd64be7c876f3bdc9bcf8d06d7c02304bbffc93e | |
parent | 9598566721fe7524cca575975ea7e8ea2e27a71b (diff) |
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/tegra/Makefile | 8 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-audio-sync.c | 87 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-divider.c | 187 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-periph-gate.c | 179 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-periph.c | 180 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-pll-out.c | 123 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 648 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-super.c | 154 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.c | 69 | ||||
-rw-r--r-- | drivers/clk/tegra/clk.h | 490 |
11 files changed, 2126 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ee90e87e7675..f0b269a2058d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ | |||
22 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o | 22 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o |
23 | obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o | 23 | obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o |
24 | obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o | 24 | obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o |
25 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | ||
25 | 26 | ||
26 | # Chip specific | 27 | # Chip specific |
27 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 28 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o |
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile new file mode 100644 index 000000000000..68bd353a2108 --- /dev/null +++ b/drivers/clk/tegra/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | obj-y += clk.o | ||
2 | obj-y += clk-audio-sync.o | ||
3 | obj-y += clk-divider.o | ||
4 | obj-y += clk-periph.o | ||
5 | obj-y += clk-periph-gate.o | ||
6 | obj-y += clk-pll.o | ||
7 | obj-y += clk-pll-out.o | ||
8 | obj-y += clk-super.o | ||
diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c new file mode 100644 index 000000000000..c0f7843e80e6 --- /dev/null +++ b/drivers/clk/tegra/clk-audio-sync.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk-provider.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/err.h> | ||
20 | |||
21 | #include "clk.h" | ||
22 | |||
23 | static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw, | ||
24 | unsigned long parent_rate) | ||
25 | { | ||
26 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
27 | |||
28 | return sync->rate; | ||
29 | } | ||
30 | |||
31 | static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate, | ||
32 | unsigned long *prate) | ||
33 | { | ||
34 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
35 | |||
36 | if (rate > sync->max_rate) | ||
37 | return -EINVAL; | ||
38 | else | ||
39 | return rate; | ||
40 | } | ||
41 | |||
42 | static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, | ||
43 | unsigned long parent_rate) | ||
44 | { | ||
45 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
46 | |||
47 | sync->rate = rate; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | const struct clk_ops tegra_clk_sync_source_ops = { | ||
52 | .round_rate = clk_sync_source_round_rate, | ||
53 | .set_rate = clk_sync_source_set_rate, | ||
54 | .recalc_rate = clk_sync_source_recalc_rate, | ||
55 | }; | ||
56 | |||
57 | struct clk *tegra_clk_register_sync_source(const char *name, | ||
58 | unsigned long rate, unsigned long max_rate) | ||
59 | { | ||
60 | struct tegra_clk_sync_source *sync; | ||
61 | struct clk_init_data init; | ||
62 | struct clk *clk; | ||
63 | |||
64 | sync = kzalloc(sizeof(*sync), GFP_KERNEL); | ||
65 | if (!sync) { | ||
66 | pr_err("%s: could not allocate sync source clk\n", __func__); | ||
67 | return ERR_PTR(-ENOMEM); | ||
68 | } | ||
69 | |||
70 | sync->rate = rate; | ||
71 | sync->max_rate = max_rate; | ||
72 | |||
73 | init.ops = &tegra_clk_sync_source_ops; | ||
74 | init.name = name; | ||
75 | init.flags = CLK_IS_ROOT; | ||
76 | init.parent_names = NULL; | ||
77 | init.num_parents = 0; | ||
78 | |||
79 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
80 | sync->hw.init = &init; | ||
81 | |||
82 | clk = clk_register(NULL, &sync->hw); | ||
83 | if (IS_ERR(clk)) | ||
84 | kfree(sync); | ||
85 | |||
86 | return clk; | ||
87 | } | ||
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c new file mode 100644 index 000000000000..4d75b1f37e3a --- /dev/null +++ b/drivers/clk/tegra/clk-divider.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/clk-provider.h> | ||
22 | #include <linux/clk.h> | ||
23 | |||
24 | #include "clk.h" | ||
25 | |||
26 | #define pll_out_override(p) (BIT((p->shift - 6))) | ||
27 | #define div_mask(d) ((1 << (d->width)) - 1) | ||
28 | #define get_mul(d) (1 << d->frac_width) | ||
29 | #define get_max_div(d) div_mask(d) | ||
30 | |||
31 | #define PERIPH_CLK_UART_DIV_ENB BIT(24) | ||
32 | |||
33 | static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, | ||
34 | unsigned long parent_rate) | ||
35 | { | ||
36 | s64 divider_ux1 = parent_rate; | ||
37 | u8 flags = divider->flags; | ||
38 | int mul; | ||
39 | |||
40 | if (!rate) | ||
41 | return 0; | ||
42 | |||
43 | mul = get_mul(divider); | ||
44 | |||
45 | if (!(flags & TEGRA_DIVIDER_INT)) | ||
46 | divider_ux1 *= mul; | ||
47 | |||
48 | if (flags & TEGRA_DIVIDER_ROUND_UP) | ||
49 | divider_ux1 += rate - 1; | ||
50 | |||
51 | do_div(divider_ux1, rate); | ||
52 | |||
53 | if (flags & TEGRA_DIVIDER_INT) | ||
54 | divider_ux1 *= mul; | ||
55 | |||
56 | divider_ux1 -= mul; | ||
57 | |||
58 | if (divider_ux1 < 0) | ||
59 | return 0; | ||
60 | |||
61 | if (divider_ux1 > get_max_div(divider)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | return divider_ux1; | ||
65 | } | ||
66 | |||
67 | static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, | ||
68 | unsigned long parent_rate) | ||
69 | { | ||
70 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
71 | u32 reg; | ||
72 | int div, mul; | ||
73 | u64 rate = parent_rate; | ||
74 | |||
75 | reg = readl_relaxed(divider->reg) >> divider->shift; | ||
76 | div = reg & div_mask(divider); | ||
77 | |||
78 | mul = get_mul(divider); | ||
79 | div += mul; | ||
80 | |||
81 | rate *= mul; | ||
82 | rate += div - 1; | ||
83 | do_div(rate, div); | ||
84 | |||
85 | return rate; | ||
86 | } | ||
87 | |||
88 | static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
89 | unsigned long *prate) | ||
90 | { | ||
91 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
92 | int div, mul; | ||
93 | unsigned long output_rate = *prate; | ||
94 | |||
95 | if (!rate) | ||
96 | return output_rate; | ||
97 | |||
98 | div = get_div(divider, rate, output_rate); | ||
99 | if (div < 0) | ||
100 | return *prate; | ||
101 | |||
102 | mul = get_mul(divider); | ||
103 | |||
104 | return DIV_ROUND_UP(output_rate * mul, div + mul); | ||
105 | } | ||
106 | |||
107 | static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
108 | unsigned long parent_rate) | ||
109 | { | ||
110 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
111 | int div; | ||
112 | unsigned long flags = 0; | ||
113 | u32 val; | ||
114 | |||
115 | div = get_div(divider, rate, parent_rate); | ||
116 | if (div < 0) | ||
117 | return div; | ||
118 | |||
119 | if (divider->lock) | ||
120 | spin_lock_irqsave(divider->lock, flags); | ||
121 | |||
122 | val = readl_relaxed(divider->reg); | ||
123 | val &= ~(div_mask(divider) << divider->shift); | ||
124 | val |= div << divider->shift; | ||
125 | |||
126 | if (divider->flags & TEGRA_DIVIDER_UART) { | ||
127 | if (div) | ||
128 | val |= PERIPH_CLK_UART_DIV_ENB; | ||
129 | else | ||
130 | val &= ~PERIPH_CLK_UART_DIV_ENB; | ||
131 | } | ||
132 | |||
133 | if (divider->flags & TEGRA_DIVIDER_FIXED) | ||
134 | val |= pll_out_override(divider); | ||
135 | |||
136 | writel_relaxed(val, divider->reg); | ||
137 | |||
138 | if (divider->lock) | ||
139 | spin_unlock_irqrestore(divider->lock, flags); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | const struct clk_ops tegra_clk_frac_div_ops = { | ||
145 | .recalc_rate = clk_frac_div_recalc_rate, | ||
146 | .set_rate = clk_frac_div_set_rate, | ||
147 | .round_rate = clk_frac_div_round_rate, | ||
148 | }; | ||
149 | |||
150 | struct clk *tegra_clk_register_divider(const char *name, | ||
151 | const char *parent_name, void __iomem *reg, | ||
152 | unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, | ||
153 | u8 frac_width, spinlock_t *lock) | ||
154 | { | ||
155 | struct tegra_clk_frac_div *divider; | ||
156 | struct clk *clk; | ||
157 | struct clk_init_data init; | ||
158 | |||
159 | divider = kzalloc(sizeof(*divider), GFP_KERNEL); | ||
160 | if (!divider) { | ||
161 | pr_err("%s: could not allocate fractional divider clk\n", | ||
162 | __func__); | ||
163 | return ERR_PTR(-ENOMEM); | ||
164 | } | ||
165 | |||
166 | init.name = name; | ||
167 | init.ops = &tegra_clk_frac_div_ops; | ||
168 | init.flags = flags; | ||
169 | init.parent_names = parent_name ? &parent_name : NULL; | ||
170 | init.num_parents = parent_name ? 1 : 0; | ||
171 | |||
172 | divider->reg = reg; | ||
173 | divider->shift = shift; | ||
174 | divider->width = width; | ||
175 | divider->frac_width = frac_width; | ||
176 | divider->lock = lock; | ||
177 | divider->flags = clk_divider_flags; | ||
178 | |||
179 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
180 | divider->hw.init = &init; | ||
181 | |||
182 | clk = clk_register(NULL, ÷r->hw); | ||
183 | if (IS_ERR(clk)) | ||
184 | kfree(divider); | ||
185 | |||
186 | return clk; | ||
187 | } | ||
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c new file mode 100644 index 000000000000..6dd533251e7b --- /dev/null +++ b/drivers/clk/tegra/clk-periph-gate.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/tegra-soc.h> | ||
24 | |||
25 | #include "clk.h" | ||
26 | |||
27 | static DEFINE_SPINLOCK(periph_ref_lock); | ||
28 | |||
29 | /* Macros to assist peripheral gate clock */ | ||
30 | #define read_enb(gate) \ | ||
31 | readl_relaxed(gate->clk_base + (gate->regs->enb_reg)) | ||
32 | #define write_enb_set(val, gate) \ | ||
33 | writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg)) | ||
34 | #define write_enb_clr(val, gate) \ | ||
35 | writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg)) | ||
36 | |||
37 | #define read_rst(gate) \ | ||
38 | readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) | ||
39 | #define write_rst_set(val, gate) \ | ||
40 | writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) | ||
41 | #define write_rst_clr(val, gate) \ | ||
42 | writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) | ||
43 | |||
44 | #define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32)) | ||
45 | |||
46 | /* Peripheral gate clock ops */ | ||
47 | static int clk_periph_is_enabled(struct clk_hw *hw) | ||
48 | { | ||
49 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
50 | int state = 1; | ||
51 | |||
52 | if (!(read_enb(gate) & periph_clk_to_bit(gate))) | ||
53 | state = 0; | ||
54 | |||
55 | if (!(gate->flags & TEGRA_PERIPH_NO_RESET)) | ||
56 | if (read_rst(gate) & periph_clk_to_bit(gate)) | ||
57 | state = 0; | ||
58 | |||
59 | return state; | ||
60 | } | ||
61 | |||
62 | static int clk_periph_enable(struct clk_hw *hw) | ||
63 | { | ||
64 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
65 | unsigned long flags = 0; | ||
66 | |||
67 | spin_lock_irqsave(&periph_ref_lock, flags); | ||
68 | |||
69 | gate->enable_refcnt[gate->clk_num]++; | ||
70 | if (gate->enable_refcnt[gate->clk_num] > 1) { | ||
71 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | write_enb_set(periph_clk_to_bit(gate), gate); | ||
76 | udelay(2); | ||
77 | |||
78 | if (!(gate->flags & TEGRA_PERIPH_NO_RESET) && | ||
79 | !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) { | ||
80 | if (read_rst(gate) & periph_clk_to_bit(gate)) { | ||
81 | udelay(5); /* reset propogation delay */ | ||
82 | write_rst_clr(periph_clk_to_bit(gate), gate); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void clk_periph_disable(struct clk_hw *hw) | ||
92 | { | ||
93 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
94 | unsigned long flags = 0; | ||
95 | |||
96 | spin_lock_irqsave(&periph_ref_lock, flags); | ||
97 | |||
98 | gate->enable_refcnt[gate->clk_num]--; | ||
99 | if (gate->enable_refcnt[gate->clk_num] > 0) { | ||
100 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * If peripheral is in the APB bus then read the APB bus to | ||
106 | * flush the write operation in apb bus. This will avoid the | ||
107 | * peripheral access after disabling clock | ||
108 | */ | ||
109 | if (gate->flags & TEGRA_PERIPH_ON_APB) | ||
110 | tegra_read_chipid(); | ||
111 | |||
112 | write_enb_clr(periph_clk_to_bit(gate), gate); | ||
113 | |||
114 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
115 | } | ||
116 | |||
117 | void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) | ||
118 | { | ||
119 | if (gate->flags & TEGRA_PERIPH_NO_RESET) | ||
120 | return; | ||
121 | |||
122 | if (assert) { | ||
123 | /* | ||
124 | * If peripheral is in the APB bus then read the APB bus to | ||
125 | * flush the write operation in apb bus. This will avoid the | ||
126 | * peripheral access after disabling clock | ||
127 | */ | ||
128 | if (gate->flags & TEGRA_PERIPH_ON_APB) | ||
129 | tegra_read_chipid(); | ||
130 | |||
131 | write_rst_set(periph_clk_to_bit(gate), gate); | ||
132 | } else { | ||
133 | write_rst_clr(periph_clk_to_bit(gate), gate); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | const struct clk_ops tegra_clk_periph_gate_ops = { | ||
138 | .is_enabled = clk_periph_is_enabled, | ||
139 | .enable = clk_periph_enable, | ||
140 | .disable = clk_periph_disable, | ||
141 | }; | ||
142 | |||
143 | struct clk *tegra_clk_register_periph_gate(const char *name, | ||
144 | const char *parent_name, u8 gate_flags, void __iomem *clk_base, | ||
145 | unsigned long flags, int clk_num, | ||
146 | struct tegra_clk_periph_regs *pregs, int *enable_refcnt) | ||
147 | { | ||
148 | struct tegra_clk_periph_gate *gate; | ||
149 | struct clk *clk; | ||
150 | struct clk_init_data init; | ||
151 | |||
152 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
153 | if (!gate) { | ||
154 | pr_err("%s: could not allocate periph gate clk\n", __func__); | ||
155 | return ERR_PTR(-ENOMEM); | ||
156 | } | ||
157 | |||
158 | init.name = name; | ||
159 | init.flags = flags; | ||
160 | init.parent_names = parent_name ? &parent_name : NULL; | ||
161 | init.num_parents = parent_name ? 1 : 0; | ||
162 | init.ops = &tegra_clk_periph_gate_ops; | ||
163 | |||
164 | gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC; | ||
165 | gate->clk_base = clk_base; | ||
166 | gate->clk_num = clk_num; | ||
167 | gate->flags = gate_flags; | ||
168 | gate->enable_refcnt = enable_refcnt; | ||
169 | gate->regs = pregs; | ||
170 | |||
171 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
172 | gate->hw.init = &init; | ||
173 | |||
174 | clk = clk_register(NULL, &gate->hw); | ||
175 | if (IS_ERR(clk)) | ||
176 | kfree(gate); | ||
177 | |||
178 | return clk; | ||
179 | } | ||
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c new file mode 100644 index 000000000000..5978e81b175b --- /dev/null +++ b/drivers/clk/tegra/clk-periph.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | #include "clk.h" | ||
23 | |||
24 | static u8 clk_periph_get_parent(struct clk_hw *hw) | ||
25 | { | ||
26 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
27 | const struct clk_ops *mux_ops = periph->mux_ops; | ||
28 | struct clk_hw *mux_hw = &periph->mux.hw; | ||
29 | |||
30 | mux_hw->clk = hw->clk; | ||
31 | |||
32 | return mux_ops->get_parent(mux_hw); | ||
33 | } | ||
34 | |||
35 | static int clk_periph_set_parent(struct clk_hw *hw, u8 index) | ||
36 | { | ||
37 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
38 | const struct clk_ops *mux_ops = periph->mux_ops; | ||
39 | struct clk_hw *mux_hw = &periph->mux.hw; | ||
40 | |||
41 | mux_hw->clk = hw->clk; | ||
42 | |||
43 | return mux_ops->set_parent(mux_hw, index); | ||
44 | } | ||
45 | |||
46 | static unsigned long clk_periph_recalc_rate(struct clk_hw *hw, | ||
47 | unsigned long parent_rate) | ||
48 | { | ||
49 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
50 | const struct clk_ops *div_ops = periph->div_ops; | ||
51 | struct clk_hw *div_hw = &periph->divider.hw; | ||
52 | |||
53 | div_hw->clk = hw->clk; | ||
54 | |||
55 | return div_ops->recalc_rate(div_hw, parent_rate); | ||
56 | } | ||
57 | |||
58 | static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate, | ||
59 | unsigned long *prate) | ||
60 | { | ||
61 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
62 | const struct clk_ops *div_ops = periph->div_ops; | ||
63 | struct clk_hw *div_hw = &periph->divider.hw; | ||
64 | |||
65 | div_hw->clk = hw->clk; | ||
66 | |||
67 | return div_ops->round_rate(div_hw, rate, prate); | ||
68 | } | ||
69 | |||
70 | static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, | ||
71 | unsigned long parent_rate) | ||
72 | { | ||
73 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
74 | const struct clk_ops *div_ops = periph->div_ops; | ||
75 | struct clk_hw *div_hw = &periph->divider.hw; | ||
76 | |||
77 | div_hw->clk = hw->clk; | ||
78 | |||
79 | return div_ops->set_rate(div_hw, rate, parent_rate); | ||
80 | } | ||
81 | |||
82 | static int clk_periph_is_enabled(struct clk_hw *hw) | ||
83 | { | ||
84 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
85 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
86 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
87 | |||
88 | gate_hw->clk = hw->clk; | ||
89 | |||
90 | return gate_ops->is_enabled(gate_hw); | ||
91 | } | ||
92 | |||
93 | static int clk_periph_enable(struct clk_hw *hw) | ||
94 | { | ||
95 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
96 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
97 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
98 | |||
99 | gate_hw->clk = hw->clk; | ||
100 | |||
101 | return gate_ops->enable(gate_hw); | ||
102 | } | ||
103 | |||
104 | static void clk_periph_disable(struct clk_hw *hw) | ||
105 | { | ||
106 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
107 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
108 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
109 | |||
110 | gate_ops->disable(gate_hw); | ||
111 | } | ||
112 | |||
113 | const struct clk_ops tegra_clk_periph_ops = { | ||
114 | .get_parent = clk_periph_get_parent, | ||
115 | .set_parent = clk_periph_set_parent, | ||
116 | .recalc_rate = clk_periph_recalc_rate, | ||
117 | .round_rate = clk_periph_round_rate, | ||
118 | .set_rate = clk_periph_set_rate, | ||
119 | .is_enabled = clk_periph_is_enabled, | ||
120 | .enable = clk_periph_enable, | ||
121 | .disable = clk_periph_disable, | ||
122 | }; | ||
123 | |||
124 | const struct clk_ops tegra_clk_periph_nodiv_ops = { | ||
125 | .get_parent = clk_periph_get_parent, | ||
126 | .set_parent = clk_periph_set_parent, | ||
127 | .is_enabled = clk_periph_is_enabled, | ||
128 | .enable = clk_periph_enable, | ||
129 | .disable = clk_periph_disable, | ||
130 | }; | ||
131 | |||
132 | static struct clk *_tegra_clk_register_periph(const char *name, | ||
133 | const char **parent_names, int num_parents, | ||
134 | struct tegra_clk_periph *periph, | ||
135 | void __iomem *clk_base, u32 offset, bool div) | ||
136 | { | ||
137 | struct clk *clk; | ||
138 | struct clk_init_data init; | ||
139 | |||
140 | init.name = name; | ||
141 | init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; | ||
142 | init.flags = div ? 0 : CLK_SET_RATE_PARENT; | ||
143 | init.parent_names = parent_names; | ||
144 | init.num_parents = num_parents; | ||
145 | |||
146 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
147 | periph->hw.init = &init; | ||
148 | periph->magic = TEGRA_CLK_PERIPH_MAGIC; | ||
149 | periph->mux.reg = clk_base + offset; | ||
150 | periph->divider.reg = div ? (clk_base + offset) : NULL; | ||
151 | periph->gate.clk_base = clk_base; | ||
152 | |||
153 | clk = clk_register(NULL, &periph->hw); | ||
154 | if (IS_ERR(clk)) | ||
155 | return clk; | ||
156 | |||
157 | periph->mux.hw.clk = clk; | ||
158 | periph->divider.hw.clk = div ? clk : NULL; | ||
159 | periph->gate.hw.clk = clk; | ||
160 | |||
161 | return clk; | ||
162 | } | ||
163 | |||
164 | struct clk *tegra_clk_register_periph(const char *name, | ||
165 | const char **parent_names, int num_parents, | ||
166 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
167 | u32 offset) | ||
168 | { | ||
169 | return _tegra_clk_register_periph(name, parent_names, num_parents, | ||
170 | periph, clk_base, offset, true); | ||
171 | } | ||
172 | |||
173 | struct clk *tegra_clk_register_periph_nodiv(const char *name, | ||
174 | const char **parent_names, int num_parents, | ||
175 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
176 | u32 offset) | ||
177 | { | ||
178 | return _tegra_clk_register_periph(name, parent_names, num_parents, | ||
179 | periph, clk_base, offset, false); | ||
180 | } | ||
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c new file mode 100644 index 000000000000..3598987a451d --- /dev/null +++ b/drivers/clk/tegra/clk-pll-out.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/clk-provider.h> | ||
23 | #include <linux/clk.h> | ||
24 | |||
25 | #include "clk.h" | ||
26 | |||
27 | #define pll_out_enb(p) (BIT(p->enb_bit_idx)) | ||
28 | #define pll_out_rst(p) (BIT(p->rst_bit_idx)) | ||
29 | |||
30 | static int clk_pll_out_is_enabled(struct clk_hw *hw) | ||
31 | { | ||
32 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
33 | u32 val = readl_relaxed(pll_out->reg); | ||
34 | int state; | ||
35 | |||
36 | state = (val & pll_out_enb(pll_out)) ? 1 : 0; | ||
37 | if (!(val & (pll_out_rst(pll_out)))) | ||
38 | state = 0; | ||
39 | return state; | ||
40 | } | ||
41 | |||
42 | static int clk_pll_out_enable(struct clk_hw *hw) | ||
43 | { | ||
44 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
45 | unsigned long flags = 0; | ||
46 | u32 val; | ||
47 | |||
48 | if (pll_out->lock) | ||
49 | spin_lock_irqsave(pll_out->lock, flags); | ||
50 | |||
51 | val = readl_relaxed(pll_out->reg); | ||
52 | |||
53 | val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out)); | ||
54 | |||
55 | writel_relaxed(val, pll_out->reg); | ||
56 | udelay(2); | ||
57 | |||
58 | if (pll_out->lock) | ||
59 | spin_unlock_irqrestore(pll_out->lock, flags); | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static void clk_pll_out_disable(struct clk_hw *hw) | ||
65 | { | ||
66 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
67 | unsigned long flags = 0; | ||
68 | u32 val; | ||
69 | |||
70 | if (pll_out->lock) | ||
71 | spin_lock_irqsave(pll_out->lock, flags); | ||
72 | |||
73 | val = readl_relaxed(pll_out->reg); | ||
74 | |||
75 | val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out)); | ||
76 | |||
77 | writel_relaxed(val, pll_out->reg); | ||
78 | udelay(2); | ||
79 | |||
80 | if (pll_out->lock) | ||
81 | spin_unlock_irqrestore(pll_out->lock, flags); | ||
82 | } | ||
83 | |||
84 | const struct clk_ops tegra_clk_pll_out_ops = { | ||
85 | .is_enabled = clk_pll_out_is_enabled, | ||
86 | .enable = clk_pll_out_enable, | ||
87 | .disable = clk_pll_out_disable, | ||
88 | }; | ||
89 | |||
90 | struct clk *tegra_clk_register_pll_out(const char *name, | ||
91 | const char *parent_name, void __iomem *reg, u8 enb_bit_idx, | ||
92 | u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags, | ||
93 | spinlock_t *lock) | ||
94 | { | ||
95 | struct tegra_clk_pll_out *pll_out; | ||
96 | struct clk *clk; | ||
97 | struct clk_init_data init; | ||
98 | |||
99 | pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL); | ||
100 | if (!pll_out) | ||
101 | return ERR_PTR(-ENOMEM); | ||
102 | |||
103 | init.name = name; | ||
104 | init.ops = &tegra_clk_pll_out_ops; | ||
105 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
106 | init.num_parents = (parent_name ? 1 : 0); | ||
107 | init.flags = flags; | ||
108 | |||
109 | pll_out->reg = reg; | ||
110 | pll_out->enb_bit_idx = enb_bit_idx; | ||
111 | pll_out->rst_bit_idx = rst_bit_idx; | ||
112 | pll_out->flags = pll_out_flags; | ||
113 | pll_out->lock = lock; | ||
114 | |||
115 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
116 | pll_out->hw.init = &init; | ||
117 | |||
118 | clk = clk_register(NULL, &pll_out->hw); | ||
119 | if (IS_ERR(clk)) | ||
120 | kfree(pll_out); | ||
121 | |||
122 | return clk; | ||
123 | } | ||
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c new file mode 100644 index 000000000000..165f24734c1b --- /dev/null +++ b/drivers/clk/tegra/clk-pll.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/slab.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/clk-provider.h> | ||
22 | #include <linux/clk.h> | ||
23 | |||
24 | #include "clk.h" | ||
25 | |||
26 | #define PLL_BASE_BYPASS BIT(31) | ||
27 | #define PLL_BASE_ENABLE BIT(30) | ||
28 | #define PLL_BASE_REF_ENABLE BIT(29) | ||
29 | #define PLL_BASE_OVERRIDE BIT(28) | ||
30 | |||
31 | #define PLL_BASE_DIVP_SHIFT 20 | ||
32 | #define PLL_BASE_DIVP_WIDTH 3 | ||
33 | #define PLL_BASE_DIVN_SHIFT 8 | ||
34 | #define PLL_BASE_DIVN_WIDTH 10 | ||
35 | #define PLL_BASE_DIVM_SHIFT 0 | ||
36 | #define PLL_BASE_DIVM_WIDTH 5 | ||
37 | #define PLLU_POST_DIVP_MASK 0x1 | ||
38 | |||
39 | #define PLL_MISC_DCCON_SHIFT 20 | ||
40 | #define PLL_MISC_CPCON_SHIFT 8 | ||
41 | #define PLL_MISC_CPCON_WIDTH 4 | ||
42 | #define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1) | ||
43 | #define PLL_MISC_LFCON_SHIFT 4 | ||
44 | #define PLL_MISC_LFCON_WIDTH 4 | ||
45 | #define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1) | ||
46 | #define PLL_MISC_VCOCON_SHIFT 0 | ||
47 | #define PLL_MISC_VCOCON_WIDTH 4 | ||
48 | #define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1) | ||
49 | |||
50 | #define OUT_OF_TABLE_CPCON 8 | ||
51 | |||
52 | #define PMC_PLLP_WB0_OVERRIDE 0xf8 | ||
53 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) | ||
54 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11) | ||
55 | |||
56 | #define PLL_POST_LOCK_DELAY 50 | ||
57 | |||
58 | #define PLLDU_LFCON_SET_DIVN 600 | ||
59 | |||
60 | #define PLLE_BASE_DIVCML_SHIFT 24 | ||
61 | #define PLLE_BASE_DIVCML_WIDTH 4 | ||
62 | #define PLLE_BASE_DIVP_SHIFT 16 | ||
63 | #define PLLE_BASE_DIVP_WIDTH 7 | ||
64 | #define PLLE_BASE_DIVN_SHIFT 8 | ||
65 | #define PLLE_BASE_DIVN_WIDTH 8 | ||
66 | #define PLLE_BASE_DIVM_SHIFT 0 | ||
67 | #define PLLE_BASE_DIVM_WIDTH 8 | ||
68 | |||
69 | #define PLLE_MISC_SETUP_BASE_SHIFT 16 | ||
70 | #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT) | ||
71 | #define PLLE_MISC_LOCK_ENABLE BIT(9) | ||
72 | #define PLLE_MISC_READY BIT(15) | ||
73 | #define PLLE_MISC_SETUP_EX_SHIFT 2 | ||
74 | #define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT) | ||
75 | #define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \ | ||
76 | PLLE_MISC_SETUP_EX_MASK) | ||
77 | #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) | ||
78 | |||
79 | #define PLLE_SS_CTRL 0x68 | ||
80 | #define PLLE_SS_DISABLE (7 << 10) | ||
81 | |||
82 | #define PMC_SATA_PWRGT 0x1ac | ||
83 | #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) | ||
84 | #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) | ||
85 | |||
86 | #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) | ||
87 | #define pll_readl_base(p) pll_readl(p->params->base_reg, p) | ||
88 | #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) | ||
89 | |||
90 | #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset) | ||
91 | #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p) | ||
92 | #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) | ||
93 | |||
94 | #define mask(w) ((1 << (w)) - 1) | ||
95 | #define divm_mask(p) mask(p->divm_width) | ||
96 | #define divn_mask(p) mask(p->divn_width) | ||
97 | #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ | ||
98 | mask(p->divp_width)) | ||
99 | |||
100 | #define divm_max(p) (divm_mask(p)) | ||
101 | #define divn_max(p) (divn_mask(p)) | ||
102 | #define divp_max(p) (1 << (divp_mask(p))) | ||
103 | |||
104 | static void clk_pll_enable_lock(struct tegra_clk_pll *pll) | ||
105 | { | ||
106 | u32 val; | ||
107 | |||
108 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) | ||
109 | return; | ||
110 | |||
111 | val = pll_readl_misc(pll); | ||
112 | val |= BIT(pll->params->lock_enable_bit_idx); | ||
113 | pll_writel_misc(val, pll); | ||
114 | } | ||
115 | |||
116 | static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, | ||
117 | void __iomem *lock_addr, u32 lock_bit_idx) | ||
118 | { | ||
119 | int i; | ||
120 | u32 val; | ||
121 | |||
122 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { | ||
123 | udelay(pll->params->lock_delay); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | for (i = 0; i < pll->params->lock_delay; i++) { | ||
128 | val = readl_relaxed(lock_addr); | ||
129 | if (val & BIT(lock_bit_idx)) { | ||
130 | udelay(PLL_POST_LOCK_DELAY); | ||
131 | return 0; | ||
132 | } | ||
133 | udelay(2); /* timeout = 2 * lock time */ | ||
134 | } | ||
135 | |||
136 | pr_err("%s: Timed out waiting for pll %s lock\n", __func__, | ||
137 | __clk_get_name(pll->hw.clk)); | ||
138 | |||
139 | return -1; | ||
140 | } | ||
141 | |||
142 | static int clk_pll_is_enabled(struct clk_hw *hw) | ||
143 | { | ||
144 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
145 | u32 val; | ||
146 | |||
147 | if (pll->flags & TEGRA_PLLM) { | ||
148 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
149 | if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) | ||
150 | return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; | ||
151 | } | ||
152 | |||
153 | val = pll_readl_base(pll); | ||
154 | |||
155 | return val & PLL_BASE_ENABLE ? 1 : 0; | ||
156 | } | ||
157 | |||
158 | static int _clk_pll_enable(struct clk_hw *hw) | ||
159 | { | ||
160 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
161 | u32 val; | ||
162 | |||
163 | clk_pll_enable_lock(pll); | ||
164 | |||
165 | val = pll_readl_base(pll); | ||
166 | val &= ~PLL_BASE_BYPASS; | ||
167 | val |= PLL_BASE_ENABLE; | ||
168 | pll_writel_base(val, pll); | ||
169 | |||
170 | if (pll->flags & TEGRA_PLLM) { | ||
171 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
172 | val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | ||
173 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
174 | } | ||
175 | |||
176 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, | ||
177 | pll->params->lock_bit_idx); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static void _clk_pll_disable(struct clk_hw *hw) | ||
183 | { | ||
184 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
185 | u32 val; | ||
186 | |||
187 | val = pll_readl_base(pll); | ||
188 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
189 | pll_writel_base(val, pll); | ||
190 | |||
191 | if (pll->flags & TEGRA_PLLM) { | ||
192 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
193 | val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | ||
194 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static int clk_pll_enable(struct clk_hw *hw) | ||
199 | { | ||
200 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
201 | unsigned long flags = 0; | ||
202 | int ret; | ||
203 | |||
204 | if (pll->lock) | ||
205 | spin_lock_irqsave(pll->lock, flags); | ||
206 | |||
207 | ret = _clk_pll_enable(hw); | ||
208 | |||
209 | if (pll->lock) | ||
210 | spin_unlock_irqrestore(pll->lock, flags); | ||
211 | |||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | static void clk_pll_disable(struct clk_hw *hw) | ||
216 | { | ||
217 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
218 | unsigned long flags = 0; | ||
219 | |||
220 | if (pll->lock) | ||
221 | spin_lock_irqsave(pll->lock, flags); | ||
222 | |||
223 | _clk_pll_disable(hw); | ||
224 | |||
225 | if (pll->lock) | ||
226 | spin_unlock_irqrestore(pll->lock, flags); | ||
227 | } | ||
228 | |||
229 | static int _get_table_rate(struct clk_hw *hw, | ||
230 | struct tegra_clk_pll_freq_table *cfg, | ||
231 | unsigned long rate, unsigned long parent_rate) | ||
232 | { | ||
233 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
234 | struct tegra_clk_pll_freq_table *sel; | ||
235 | |||
236 | for (sel = pll->freq_table; sel->input_rate != 0; sel++) | ||
237 | if (sel->input_rate == parent_rate && | ||
238 | sel->output_rate == rate) | ||
239 | break; | ||
240 | |||
241 | if (sel->input_rate == 0) | ||
242 | return -EINVAL; | ||
243 | |||
244 | BUG_ON(sel->p < 1); | ||
245 | |||
246 | cfg->input_rate = sel->input_rate; | ||
247 | cfg->output_rate = sel->output_rate; | ||
248 | cfg->m = sel->m; | ||
249 | cfg->n = sel->n; | ||
250 | cfg->p = sel->p; | ||
251 | cfg->cpcon = sel->cpcon; | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | ||
257 | unsigned long rate, unsigned long parent_rate) | ||
258 | { | ||
259 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
260 | unsigned long cfreq; | ||
261 | u32 p_div = 0; | ||
262 | |||
263 | switch (parent_rate) { | ||
264 | case 12000000: | ||
265 | case 26000000: | ||
266 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; | ||
267 | break; | ||
268 | case 13000000: | ||
269 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; | ||
270 | break; | ||
271 | case 16800000: | ||
272 | case 19200000: | ||
273 | cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; | ||
274 | break; | ||
275 | case 9600000: | ||
276 | case 28800000: | ||
277 | /* | ||
278 | * PLL_P_OUT1 rate is not listed in PLLA table | ||
279 | */ | ||
280 | cfreq = parent_rate/(parent_rate/1000000); | ||
281 | break; | ||
282 | default: | ||
283 | pr_err("%s Unexpected reference rate %lu\n", | ||
284 | __func__, parent_rate); | ||
285 | BUG(); | ||
286 | } | ||
287 | |||
288 | /* Raise VCO to guarantee 0.5% accuracy */ | ||
289 | for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq; | ||
290 | cfg->output_rate <<= 1) | ||
291 | p_div++; | ||
292 | |||
293 | cfg->p = 1 << p_div; | ||
294 | cfg->m = parent_rate / cfreq; | ||
295 | cfg->n = cfg->output_rate / cfreq; | ||
296 | cfg->cpcon = OUT_OF_TABLE_CPCON; | ||
297 | |||
298 | if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || | ||
299 | cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { | ||
300 | pr_err("%s: Failed to set %s rate %lu\n", | ||
301 | __func__, __clk_get_name(hw->clk), rate); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | ||
309 | unsigned long rate) | ||
310 | { | ||
311 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
312 | unsigned long flags = 0; | ||
313 | u32 divp, val, old_base; | ||
314 | int state; | ||
315 | |||
316 | divp = __ffs(cfg->p); | ||
317 | |||
318 | if (pll->flags & TEGRA_PLLU) | ||
319 | divp ^= 1; | ||
320 | |||
321 | if (pll->lock) | ||
322 | spin_lock_irqsave(pll->lock, flags); | ||
323 | |||
324 | old_base = val = pll_readl_base(pll); | ||
325 | val &= ~((divm_mask(pll) << pll->divm_shift) | | ||
326 | (divn_mask(pll) << pll->divn_shift) | | ||
327 | (divp_mask(pll) << pll->divp_shift)); | ||
328 | val |= ((cfg->m << pll->divm_shift) | | ||
329 | (cfg->n << pll->divn_shift) | | ||
330 | (divp << pll->divp_shift)); | ||
331 | if (val == old_base) { | ||
332 | if (pll->lock) | ||
333 | spin_unlock_irqrestore(pll->lock, flags); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | state = clk_pll_is_enabled(hw); | ||
338 | |||
339 | if (state) { | ||
340 | _clk_pll_disable(hw); | ||
341 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
342 | } | ||
343 | pll_writel_base(val, pll); | ||
344 | |||
345 | if (pll->flags & TEGRA_PLL_HAS_CPCON) { | ||
346 | val = pll_readl_misc(pll); | ||
347 | val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); | ||
348 | val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; | ||
349 | if (pll->flags & TEGRA_PLL_SET_LFCON) { | ||
350 | val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); | ||
351 | if (cfg->n >= PLLDU_LFCON_SET_DIVN) | ||
352 | val |= 0x1 << PLL_MISC_LFCON_SHIFT; | ||
353 | } else if (pll->flags & TEGRA_PLL_SET_DCCON) { | ||
354 | val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); | ||
355 | if (rate >= (pll->params->vco_max >> 1)) | ||
356 | val |= 0x1 << PLL_MISC_DCCON_SHIFT; | ||
357 | } | ||
358 | pll_writel_misc(val, pll); | ||
359 | } | ||
360 | |||
361 | if (pll->lock) | ||
362 | spin_unlock_irqrestore(pll->lock, flags); | ||
363 | |||
364 | if (state) | ||
365 | clk_pll_enable(hw); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
371 | unsigned long parent_rate) | ||
372 | { | ||
373 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
374 | struct tegra_clk_pll_freq_table cfg; | ||
375 | |||
376 | if (pll->flags & TEGRA_PLL_FIXED) { | ||
377 | if (rate != pll->fixed_rate) { | ||
378 | pr_err("%s: Can not change %s fixed rate %lu to %lu\n", | ||
379 | __func__, __clk_get_name(hw->clk), | ||
380 | pll->fixed_rate, rate); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | if (_get_table_rate(hw, &cfg, rate, parent_rate) && | ||
387 | _calc_rate(hw, &cfg, rate, parent_rate)) | ||
388 | return -EINVAL; | ||
389 | |||
390 | return _program_pll(hw, &cfg, rate); | ||
391 | } | ||
392 | |||
393 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
394 | unsigned long *prate) | ||
395 | { | ||
396 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
397 | struct tegra_clk_pll_freq_table cfg; | ||
398 | u64 output_rate = *prate; | ||
399 | |||
400 | if (pll->flags & TEGRA_PLL_FIXED) | ||
401 | return pll->fixed_rate; | ||
402 | |||
403 | /* PLLM is used for memory; we do not change rate */ | ||
404 | if (pll->flags & TEGRA_PLLM) | ||
405 | return __clk_get_rate(hw->clk); | ||
406 | |||
407 | if (_get_table_rate(hw, &cfg, rate, *prate) && | ||
408 | _calc_rate(hw, &cfg, rate, *prate)) | ||
409 | return -EINVAL; | ||
410 | |||
411 | output_rate *= cfg.n; | ||
412 | do_div(output_rate, cfg.m * cfg.p); | ||
413 | |||
414 | return output_rate; | ||
415 | } | ||
416 | |||
417 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | ||
418 | unsigned long parent_rate) | ||
419 | { | ||
420 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
421 | u32 val = pll_readl_base(pll); | ||
422 | u32 divn = 0, divm = 0, divp = 0; | ||
423 | u64 rate = parent_rate; | ||
424 | |||
425 | if (val & PLL_BASE_BYPASS) | ||
426 | return parent_rate; | ||
427 | |||
428 | if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { | ||
429 | struct tegra_clk_pll_freq_table sel; | ||
430 | if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { | ||
431 | pr_err("Clock %s has unknown fixed frequency\n", | ||
432 | __clk_get_name(hw->clk)); | ||
433 | BUG(); | ||
434 | } | ||
435 | return pll->fixed_rate; | ||
436 | } | ||
437 | |||
438 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | ||
439 | if (pll->flags & TEGRA_PLLU) | ||
440 | divp ^= 1; | ||
441 | |||
442 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | ||
443 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | ||
444 | divm *= (1 << divp); | ||
445 | |||
446 | rate *= divn; | ||
447 | do_div(rate, divm); | ||
448 | return rate; | ||
449 | } | ||
450 | |||
451 | static int clk_plle_training(struct tegra_clk_pll *pll) | ||
452 | { | ||
453 | u32 val; | ||
454 | unsigned long timeout; | ||
455 | |||
456 | if (!pll->pmc) | ||
457 | return -ENOSYS; | ||
458 | |||
459 | /* | ||
460 | * PLLE is already disabled, and setup cleared; | ||
461 | * create falling edge on PLLE IDDQ input. | ||
462 | */ | ||
463 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
464 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | ||
465 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
466 | |||
467 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
468 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; | ||
469 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
470 | |||
471 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
472 | val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | ||
473 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
474 | |||
475 | val = pll_readl_misc(pll); | ||
476 | |||
477 | timeout = jiffies + msecs_to_jiffies(100); | ||
478 | while (1) { | ||
479 | val = pll_readl_misc(pll); | ||
480 | if (val & PLLE_MISC_READY) | ||
481 | break; | ||
482 | if (time_after(jiffies, timeout)) { | ||
483 | pr_err("%s: timeout waiting for PLLE\n", __func__); | ||
484 | return -EBUSY; | ||
485 | } | ||
486 | udelay(300); | ||
487 | } | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int clk_plle_enable(struct clk_hw *hw) | ||
493 | { | ||
494 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
495 | unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); | ||
496 | struct tegra_clk_pll_freq_table sel; | ||
497 | u32 val; | ||
498 | int err; | ||
499 | |||
500 | if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) | ||
501 | return -EINVAL; | ||
502 | |||
503 | clk_pll_disable(hw); | ||
504 | |||
505 | val = pll_readl_misc(pll); | ||
506 | val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); | ||
507 | pll_writel_misc(val, pll); | ||
508 | |||
509 | val = pll_readl_misc(pll); | ||
510 | if (!(val & PLLE_MISC_READY)) { | ||
511 | err = clk_plle_training(pll); | ||
512 | if (err) | ||
513 | return err; | ||
514 | } | ||
515 | |||
516 | if (pll->flags & TEGRA_PLLE_CONFIGURE) { | ||
517 | /* configure dividers */ | ||
518 | val = pll_readl_base(pll); | ||
519 | val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); | ||
520 | val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); | ||
521 | val |= sel.m << pll->divm_shift; | ||
522 | val |= sel.n << pll->divn_shift; | ||
523 | val |= sel.p << pll->divp_shift; | ||
524 | val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; | ||
525 | pll_writel_base(val, pll); | ||
526 | } | ||
527 | |||
528 | val = pll_readl_misc(pll); | ||
529 | val |= PLLE_MISC_SETUP_VALUE; | ||
530 | val |= PLLE_MISC_LOCK_ENABLE; | ||
531 | pll_writel_misc(val, pll); | ||
532 | |||
533 | val = readl(pll->clk_base + PLLE_SS_CTRL); | ||
534 | val |= PLLE_SS_DISABLE; | ||
535 | writel(val, pll->clk_base + PLLE_SS_CTRL); | ||
536 | |||
537 | val |= pll_readl_base(pll); | ||
538 | val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
539 | pll_writel_base(val, pll); | ||
540 | |||
541 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, | ||
542 | pll->params->lock_bit_idx); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, | ||
547 | unsigned long parent_rate) | ||
548 | { | ||
549 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
550 | u32 val = pll_readl_base(pll); | ||
551 | u32 divn = 0, divm = 0, divp = 0; | ||
552 | u64 rate = parent_rate; | ||
553 | |||
554 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | ||
555 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | ||
556 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | ||
557 | divm *= divp; | ||
558 | |||
559 | rate *= divn; | ||
560 | do_div(rate, divm); | ||
561 | return rate; | ||
562 | } | ||
563 | |||
564 | const struct clk_ops tegra_clk_pll_ops = { | ||
565 | .is_enabled = clk_pll_is_enabled, | ||
566 | .enable = clk_pll_enable, | ||
567 | .disable = clk_pll_disable, | ||
568 | .recalc_rate = clk_pll_recalc_rate, | ||
569 | .round_rate = clk_pll_round_rate, | ||
570 | .set_rate = clk_pll_set_rate, | ||
571 | }; | ||
572 | |||
573 | const struct clk_ops tegra_clk_plle_ops = { | ||
574 | .recalc_rate = clk_plle_recalc_rate, | ||
575 | .is_enabled = clk_pll_is_enabled, | ||
576 | .disable = clk_pll_disable, | ||
577 | .enable = clk_plle_enable, | ||
578 | }; | ||
579 | |||
580 | static struct clk *_tegra_clk_register_pll(const char *name, | ||
581 | const char *parent_name, void __iomem *clk_base, | ||
582 | void __iomem *pmc, unsigned long flags, | ||
583 | unsigned long fixed_rate, | ||
584 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
585 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, | ||
586 | const struct clk_ops *ops) | ||
587 | { | ||
588 | struct tegra_clk_pll *pll; | ||
589 | struct clk *clk; | ||
590 | struct clk_init_data init; | ||
591 | |||
592 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
593 | if (!pll) | ||
594 | return ERR_PTR(-ENOMEM); | ||
595 | |||
596 | init.name = name; | ||
597 | init.ops = ops; | ||
598 | init.flags = flags; | ||
599 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
600 | init.num_parents = (parent_name ? 1 : 0); | ||
601 | |||
602 | pll->clk_base = clk_base; | ||
603 | pll->pmc = pmc; | ||
604 | |||
605 | pll->freq_table = freq_table; | ||
606 | pll->params = pll_params; | ||
607 | pll->fixed_rate = fixed_rate; | ||
608 | pll->flags = pll_flags; | ||
609 | pll->lock = lock; | ||
610 | |||
611 | pll->divp_shift = PLL_BASE_DIVP_SHIFT; | ||
612 | pll->divp_width = PLL_BASE_DIVP_WIDTH; | ||
613 | pll->divn_shift = PLL_BASE_DIVN_SHIFT; | ||
614 | pll->divn_width = PLL_BASE_DIVN_WIDTH; | ||
615 | pll->divm_shift = PLL_BASE_DIVM_SHIFT; | ||
616 | pll->divm_width = PLL_BASE_DIVM_WIDTH; | ||
617 | |||
618 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
619 | pll->hw.init = &init; | ||
620 | |||
621 | clk = clk_register(NULL, &pll->hw); | ||
622 | if (IS_ERR(clk)) | ||
623 | kfree(pll); | ||
624 | |||
625 | return clk; | ||
626 | } | ||
627 | |||
628 | struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | ||
629 | void __iomem *clk_base, void __iomem *pmc, | ||
630 | unsigned long flags, unsigned long fixed_rate, | ||
631 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
632 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | ||
633 | { | ||
634 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | ||
635 | flags, fixed_rate, pll_params, pll_flags, freq_table, | ||
636 | lock, &tegra_clk_pll_ops); | ||
637 | } | ||
638 | |||
639 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | ||
640 | void __iomem *clk_base, void __iomem *pmc, | ||
641 | unsigned long flags, unsigned long fixed_rate, | ||
642 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
643 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | ||
644 | { | ||
645 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | ||
646 | flags, fixed_rate, pll_params, pll_flags, freq_table, | ||
647 | lock, &tegra_clk_plle_ops); | ||
648 | } | ||
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c new file mode 100644 index 000000000000..7ad48a832334 --- /dev/null +++ b/drivers/clk/tegra/clk-super.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/clk-provider.h> | ||
23 | #include <linux/clk.h> | ||
24 | |||
25 | #include "clk.h" | ||
26 | |||
27 | #define SUPER_STATE_IDLE 0 | ||
28 | #define SUPER_STATE_RUN 1 | ||
29 | #define SUPER_STATE_IRQ 2 | ||
30 | #define SUPER_STATE_FIQ 3 | ||
31 | |||
32 | #define SUPER_STATE_SHIFT 28 | ||
33 | #define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ | ||
34 | BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ | ||
35 | << SUPER_STATE_SHIFT) | ||
36 | |||
37 | #define SUPER_LP_DIV2_BYPASS (1 << 16) | ||
38 | |||
39 | #define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) | ||
40 | #define super_state_to_src_shift(m, s) ((m->width * s)) | ||
41 | #define super_state_to_src_mask(m) (((1 << m->width) - 1)) | ||
42 | |||
43 | static u8 clk_super_get_parent(struct clk_hw *hw) | ||
44 | { | ||
45 | struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); | ||
46 | u32 val, state; | ||
47 | u8 source, shift; | ||
48 | |||
49 | val = readl_relaxed(mux->reg); | ||
50 | |||
51 | state = val & SUPER_STATE_MASK; | ||
52 | |||
53 | BUG_ON((state != super_state(SUPER_STATE_RUN)) && | ||
54 | (state != super_state(SUPER_STATE_IDLE))); | ||
55 | shift = (state == super_state(SUPER_STATE_IDLE)) ? | ||
56 | super_state_to_src_shift(mux, SUPER_STATE_IDLE) : | ||
57 | super_state_to_src_shift(mux, SUPER_STATE_RUN); | ||
58 | |||
59 | source = (val >> shift) & super_state_to_src_mask(mux); | ||
60 | |||
61 | /* | ||
62 | * If LP_DIV2_BYPASS is not set and PLLX is current parent then | ||
63 | * PLLX/2 is the input source to CCLKLP. | ||
64 | */ | ||
65 | if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && | ||
66 | (source == mux->pllx_index)) | ||
67 | source = mux->div2_index; | ||
68 | |||
69 | return source; | ||
70 | } | ||
71 | |||
72 | static int clk_super_set_parent(struct clk_hw *hw, u8 index) | ||
73 | { | ||
74 | struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); | ||
75 | u32 val, state; | ||
76 | u8 parent_index, shift; | ||
77 | |||
78 | val = readl_relaxed(mux->reg); | ||
79 | state = val & SUPER_STATE_MASK; | ||
80 | BUG_ON((state != super_state(SUPER_STATE_RUN)) && | ||
81 | (state != super_state(SUPER_STATE_IDLE))); | ||
82 | shift = (state == super_state(SUPER_STATE_IDLE)) ? | ||
83 | super_state_to_src_shift(mux, SUPER_STATE_IDLE) : | ||
84 | super_state_to_src_shift(mux, SUPER_STATE_RUN); | ||
85 | |||
86 | /* | ||
87 | * For LP mode super-clock switch between PLLX direct | ||
88 | * and divided-by-2 outputs is allowed only when other | ||
89 | * than PLLX clock source is current parent. | ||
90 | */ | ||
91 | if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || | ||
92 | (index == mux->pllx_index))) { | ||
93 | parent_index = clk_super_get_parent(hw); | ||
94 | if ((parent_index == mux->div2_index) || | ||
95 | (parent_index == mux->pllx_index)) | ||
96 | return -EINVAL; | ||
97 | |||
98 | val ^= SUPER_LP_DIV2_BYPASS; | ||
99 | writel_relaxed(val, mux->reg); | ||
100 | udelay(2); | ||
101 | |||
102 | if (index == mux->div2_index) | ||
103 | index = mux->pllx_index; | ||
104 | } | ||
105 | val &= ~((super_state_to_src_mask(mux)) << shift); | ||
106 | val |= (index & (super_state_to_src_mask(mux))) << shift; | ||
107 | |||
108 | writel_relaxed(val, mux->reg); | ||
109 | udelay(2); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | const struct clk_ops tegra_clk_super_ops = { | ||
114 | .get_parent = clk_super_get_parent, | ||
115 | .set_parent = clk_super_set_parent, | ||
116 | }; | ||
117 | |||
118 | struct clk *tegra_clk_register_super_mux(const char *name, | ||
119 | const char **parent_names, u8 num_parents, | ||
120 | unsigned long flags, void __iomem *reg, u8 clk_super_flags, | ||
121 | u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) | ||
122 | { | ||
123 | struct tegra_clk_super_mux *super; | ||
124 | struct clk *clk; | ||
125 | struct clk_init_data init; | ||
126 | |||
127 | super = kzalloc(sizeof(*super), GFP_KERNEL); | ||
128 | if (!super) { | ||
129 | pr_err("%s: could not allocate super clk\n", __func__); | ||
130 | return ERR_PTR(-ENOMEM); | ||
131 | } | ||
132 | |||
133 | init.name = name; | ||
134 | init.ops = &tegra_clk_super_ops; | ||
135 | init.flags = flags; | ||
136 | init.parent_names = parent_names; | ||
137 | init.num_parents = num_parents; | ||
138 | |||
139 | super->reg = reg; | ||
140 | super->pllx_index = pllx_index; | ||
141 | super->div2_index = div2_index; | ||
142 | super->lock = lock; | ||
143 | super->width = width; | ||
144 | super->flags = clk_super_flags; | ||
145 | |||
146 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
147 | super->hw.init = &init; | ||
148 | |||
149 | clk = clk_register(NULL, &super->hw); | ||
150 | if (IS_ERR(clk)) | ||
151 | kfree(super); | ||
152 | |||
153 | return clk; | ||
154 | } | ||
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c new file mode 100644 index 000000000000..cf023a937208 --- /dev/null +++ b/drivers/clk/tegra/clk.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/clk-provider.h> | ||
19 | |||
20 | #include "clk.h" | ||
21 | |||
22 | void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, | ||
23 | struct clk *clks[], int clk_max) | ||
24 | { | ||
25 | struct clk *clk; | ||
26 | |||
27 | for (; dup_list->clk_id < clk_max; dup_list++) { | ||
28 | clk = clks[dup_list->clk_id]; | ||
29 | dup_list->lookup.clk = clk; | ||
30 | clkdev_add(&dup_list->lookup); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, | ||
35 | struct clk *clks[], int clk_max) | ||
36 | { | ||
37 | struct clk *clk; | ||
38 | |||
39 | for (; tbl->clk_id < clk_max; tbl++) { | ||
40 | clk = clks[tbl->clk_id]; | ||
41 | if (IS_ERR_OR_NULL(clk)) | ||
42 | return; | ||
43 | |||
44 | if (tbl->parent_id < clk_max) { | ||
45 | struct clk *parent = clks[tbl->parent_id]; | ||
46 | if (clk_set_parent(clk, parent)) { | ||
47 | pr_err("%s: Failed to set parent %s of %s\n", | ||
48 | __func__, __clk_get_name(parent), | ||
49 | __clk_get_name(clk)); | ||
50 | WARN_ON(1); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | if (tbl->rate) | ||
55 | if (clk_set_rate(clk, tbl->rate)) { | ||
56 | pr_err("%s: Failed to set rate %lu of %s\n", | ||
57 | __func__, tbl->rate, | ||
58 | __clk_get_name(clk)); | ||
59 | WARN_ON(1); | ||
60 | } | ||
61 | |||
62 | if (tbl->state) | ||
63 | if (clk_prepare_enable(clk)) { | ||
64 | pr_err("%s: Failed to enable %s\n", __func__, | ||
65 | __clk_get_name(clk)); | ||
66 | WARN_ON(1); | ||
67 | } | ||
68 | } | ||
69 | } | ||
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h new file mode 100644 index 000000000000..5fcfa51d6b17 --- /dev/null +++ b/drivers/clk/tegra/clk.h | |||
@@ -0,0 +1,490 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TEGRA_CLK_H | ||
18 | #define __TEGRA_CLK_H | ||
19 | |||
20 | #include <linux/clk-provider.h> | ||
21 | #include <linux/clkdev.h> | ||
22 | |||
23 | /** | ||
24 | * struct tegra_clk_sync_source - external clock source from codec | ||
25 | * | ||
26 | * @hw: handle between common and hardware-specific interfaces | ||
27 | * @rate: input frequency from source | ||
28 | * @max_rate: max rate allowed | ||
29 | */ | ||
30 | struct tegra_clk_sync_source { | ||
31 | struct clk_hw hw; | ||
32 | unsigned long rate; | ||
33 | unsigned long max_rate; | ||
34 | }; | ||
35 | |||
36 | #define to_clk_sync_source(_hw) \ | ||
37 | container_of(_hw, struct tegra_clk_sync_source, hw) | ||
38 | |||
39 | extern const struct clk_ops tegra_clk_sync_source_ops; | ||
40 | struct clk *tegra_clk_register_sync_source(const char *name, | ||
41 | unsigned long fixed_rate, unsigned long max_rate); | ||
42 | |||
43 | /** | ||
44 | * struct tegra_clk_frac_div - fractional divider clock | ||
45 | * | ||
46 | * @hw: handle between common and hardware-specific interfaces | ||
47 | * @reg: register containing divider | ||
48 | * @flags: hardware-specific flags | ||
49 | * @shift: shift to the divider bit field | ||
50 | * @width: width of the divider bit field | ||
51 | * @frac_width: width of the fractional bit field | ||
52 | * @lock: register lock | ||
53 | * | ||
54 | * Flags: | ||
55 | * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value. | ||
56 | * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this | ||
57 | * flag indicates that this divider is for fixed rate PLL. | ||
58 | * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when | ||
59 | * fraction bit is set. This flags indicates to calculate divider for which | ||
60 | * fracton bit will be zero. | ||
61 | * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is | ||
62 | * set when divider value is not 0. This flags indicates that the divider | ||
63 | * is for UART module. | ||
64 | */ | ||
65 | struct tegra_clk_frac_div { | ||
66 | struct clk_hw hw; | ||
67 | void __iomem *reg; | ||
68 | u8 flags; | ||
69 | u8 shift; | ||
70 | u8 width; | ||
71 | u8 frac_width; | ||
72 | spinlock_t *lock; | ||
73 | }; | ||
74 | |||
75 | #define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw) | ||
76 | |||
77 | #define TEGRA_DIVIDER_ROUND_UP BIT(0) | ||
78 | #define TEGRA_DIVIDER_FIXED BIT(1) | ||
79 | #define TEGRA_DIVIDER_INT BIT(2) | ||
80 | #define TEGRA_DIVIDER_UART BIT(3) | ||
81 | |||
82 | extern const struct clk_ops tegra_clk_frac_div_ops; | ||
83 | struct clk *tegra_clk_register_divider(const char *name, | ||
84 | const char *parent_name, void __iomem *reg, | ||
85 | unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, | ||
86 | u8 frac_width, spinlock_t *lock); | ||
87 | |||
88 | /* | ||
89 | * Tegra PLL: | ||
90 | * | ||
91 | * In general, there are 3 requirements for each PLL | ||
92 | * that SW needs to be comply with. | ||
93 | * (1) Input frequency range (REF). | ||
94 | * (2) Comparison frequency range (CF). CF = REF/DIVM. | ||
95 | * (3) VCO frequency range (VCO). VCO = CF * DIVN. | ||
96 | * | ||
97 | * The final PLL output frequency (FO) = VCO >> DIVP. | ||
98 | */ | ||
99 | |||
100 | /** | ||
101 | * struct tegra_clk_pll_freq_table - PLL frequecy table | ||
102 | * | ||
103 | * @input_rate: input rate from source | ||
104 | * @output_rate: output rate from PLL for the input rate | ||
105 | * @n: feedback divider | ||
106 | * @m: input divider | ||
107 | * @p: post divider | ||
108 | * @cpcon: charge pump current | ||
109 | */ | ||
110 | struct tegra_clk_pll_freq_table { | ||
111 | unsigned long input_rate; | ||
112 | unsigned long output_rate; | ||
113 | u16 n; | ||
114 | u16 m; | ||
115 | u8 p; | ||
116 | u8 cpcon; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * struct clk_pll_params - PLL parameters | ||
121 | * | ||
122 | * @input_min: Minimum input frequency | ||
123 | * @input_max: Maximum input frequency | ||
124 | * @cf_min: Minimum comparison frequency | ||
125 | * @cf_max: Maximum comparison frequency | ||
126 | * @vco_min: Minimum VCO frequency | ||
127 | * @vco_max: Maximum VCO frequency | ||
128 | * @base_reg: PLL base reg offset | ||
129 | * @misc_reg: PLL misc reg offset | ||
130 | * @lock_reg: PLL lock reg offset | ||
131 | * @lock_bit_idx: Bit index for PLL lock status | ||
132 | * @lock_enable_bit_idx: Bit index to enable PLL lock | ||
133 | * @lock_delay: Delay in us if PLL lock is not used | ||
134 | */ | ||
135 | struct tegra_clk_pll_params { | ||
136 | unsigned long input_min; | ||
137 | unsigned long input_max; | ||
138 | unsigned long cf_min; | ||
139 | unsigned long cf_max; | ||
140 | unsigned long vco_min; | ||
141 | unsigned long vco_max; | ||
142 | |||
143 | u32 base_reg; | ||
144 | u32 misc_reg; | ||
145 | u32 lock_reg; | ||
146 | u32 lock_bit_idx; | ||
147 | u32 lock_enable_bit_idx; | ||
148 | int lock_delay; | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * struct tegra_clk_pll - Tegra PLL clock | ||
153 | * | ||
154 | * @hw: handle between common and hardware-specifix interfaces | ||
155 | * @clk_base: address of CAR controller | ||
156 | * @pmc: address of PMC, required to read override bits | ||
157 | * @freq_table: array of frequencies supported by PLL | ||
158 | * @params: PLL parameters | ||
159 | * @flags: PLL flags | ||
160 | * @fixed_rate: PLL rate if it is fixed | ||
161 | * @lock: register lock | ||
162 | * @divn_shift: shift to the feedback divider bit field | ||
163 | * @divn_width: width of the feedback divider bit field | ||
164 | * @divm_shift: shift to the input divider bit field | ||
165 | * @divm_width: width of the input divider bit field | ||
166 | * @divp_shift: shift to the post divider bit field | ||
167 | * @divp_width: width of the post divider bit field | ||
168 | * | ||
169 | * Flags: | ||
170 | * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for | ||
171 | * PLL locking. If not set it will use lock_delay value to wait. | ||
172 | * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs | ||
173 | * to be programmed to change output frequency of the PLL. | ||
174 | * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs | ||
175 | * to be programmed to change output frequency of the PLL. | ||
176 | * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs | ||
177 | * to be programmed to change output frequency of the PLL. | ||
178 | * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated | ||
179 | * that it is PLLU and invert post divider value. | ||
180 | * TEGRA_PLLM - PLLM has additional override settings in PMC. This | ||
181 | * flag indicates that it is PLLM and use override settings. | ||
182 | * TEGRA_PLL_FIXED - We are not supposed to change output frequency | ||
183 | * of some plls. | ||
184 | * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. | ||
185 | */ | ||
186 | struct tegra_clk_pll { | ||
187 | struct clk_hw hw; | ||
188 | void __iomem *clk_base; | ||
189 | void __iomem *pmc; | ||
190 | u8 flags; | ||
191 | unsigned long fixed_rate; | ||
192 | spinlock_t *lock; | ||
193 | u8 divn_shift; | ||
194 | u8 divn_width; | ||
195 | u8 divm_shift; | ||
196 | u8 divm_width; | ||
197 | u8 divp_shift; | ||
198 | u8 divp_width; | ||
199 | struct tegra_clk_pll_freq_table *freq_table; | ||
200 | struct tegra_clk_pll_params *params; | ||
201 | }; | ||
202 | |||
203 | #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) | ||
204 | |||
205 | #define TEGRA_PLL_USE_LOCK BIT(0) | ||
206 | #define TEGRA_PLL_HAS_CPCON BIT(1) | ||
207 | #define TEGRA_PLL_SET_LFCON BIT(2) | ||
208 | #define TEGRA_PLL_SET_DCCON BIT(3) | ||
209 | #define TEGRA_PLLU BIT(4) | ||
210 | #define TEGRA_PLLM BIT(5) | ||
211 | #define TEGRA_PLL_FIXED BIT(6) | ||
212 | #define TEGRA_PLLE_CONFIGURE BIT(7) | ||
213 | |||
214 | extern const struct clk_ops tegra_clk_pll_ops; | ||
215 | extern const struct clk_ops tegra_clk_plle_ops; | ||
216 | struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | ||
217 | void __iomem *clk_base, void __iomem *pmc, | ||
218 | unsigned long flags, unsigned long fixed_rate, | ||
219 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
220 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); | ||
221 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | ||
222 | void __iomem *clk_base, void __iomem *pmc, | ||
223 | unsigned long flags, unsigned long fixed_rate, | ||
224 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
225 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); | ||
226 | |||
227 | /** | ||
228 | * struct tegra_clk_pll_out - PLL divider down clock | ||
229 | * | ||
230 | * @hw: handle between common and hardware-specific interfaces | ||
231 | * @reg: register containing the PLL divider | ||
232 | * @enb_bit_idx: bit to enable/disable PLL divider | ||
233 | * @rst_bit_idx: bit to reset PLL divider | ||
234 | * @lock: register lock | ||
235 | * @flags: hardware-specific flags | ||
236 | */ | ||
237 | struct tegra_clk_pll_out { | ||
238 | struct clk_hw hw; | ||
239 | void __iomem *reg; | ||
240 | u8 enb_bit_idx; | ||
241 | u8 rst_bit_idx; | ||
242 | spinlock_t *lock; | ||
243 | u8 flags; | ||
244 | }; | ||
245 | |||
246 | #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw) | ||
247 | |||
248 | extern const struct clk_ops tegra_clk_pll_out_ops; | ||
249 | struct clk *tegra_clk_register_pll_out(const char *name, | ||
250 | const char *parent_name, void __iomem *reg, u8 enb_bit_idx, | ||
251 | u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags, | ||
252 | spinlock_t *lock); | ||
253 | |||
254 | /** | ||
255 | * struct tegra_clk_periph_regs - Registers controlling peripheral clock | ||
256 | * | ||
257 | * @enb_reg: read the enable status | ||
258 | * @enb_set_reg: write 1 to enable clock | ||
259 | * @enb_clr_reg: write 1 to disable clock | ||
260 | * @rst_reg: read the reset status | ||
261 | * @rst_set_reg: write 1 to assert the reset of peripheral | ||
262 | * @rst_clr_reg: write 1 to deassert the reset of peripheral | ||
263 | */ | ||
264 | struct tegra_clk_periph_regs { | ||
265 | u32 enb_reg; | ||
266 | u32 enb_set_reg; | ||
267 | u32 enb_clr_reg; | ||
268 | u32 rst_reg; | ||
269 | u32 rst_set_reg; | ||
270 | u32 rst_clr_reg; | ||
271 | }; | ||
272 | |||
273 | /** | ||
274 | * struct tegra_clk_periph_gate - peripheral gate clock | ||
275 | * | ||
276 | * @magic: magic number to validate type | ||
277 | * @hw: handle between common and hardware-specific interfaces | ||
278 | * @clk_base: address of CAR controller | ||
279 | * @regs: Registers to control the peripheral | ||
280 | * @flags: hardware-specific flags | ||
281 | * @clk_num: Clock number | ||
282 | * @enable_refcnt: array to maintain reference count of the clock | ||
283 | * | ||
284 | * Flags: | ||
285 | * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed | ||
286 | * for this module. | ||
287 | * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module | ||
288 | * after clock enable and driver for the module is responsible for | ||
289 | * doing reset. | ||
290 | * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the | ||
291 | * bus to flush the write operation in apb bus. This flag indicates | ||
292 | * that this peripheral is in apb bus. | ||
293 | */ | ||
294 | struct tegra_clk_periph_gate { | ||
295 | u32 magic; | ||
296 | struct clk_hw hw; | ||
297 | void __iomem *clk_base; | ||
298 | u8 flags; | ||
299 | int clk_num; | ||
300 | int *enable_refcnt; | ||
301 | struct tegra_clk_periph_regs *regs; | ||
302 | }; | ||
303 | |||
304 | #define to_clk_periph_gate(_hw) \ | ||
305 | container_of(_hw, struct tegra_clk_periph_gate, hw) | ||
306 | |||
307 | #define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309 | ||
308 | |||
309 | #define TEGRA_PERIPH_NO_RESET BIT(0) | ||
310 | #define TEGRA_PERIPH_MANUAL_RESET BIT(1) | ||
311 | #define TEGRA_PERIPH_ON_APB BIT(2) | ||
312 | |||
313 | void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); | ||
314 | extern const struct clk_ops tegra_clk_periph_gate_ops; | ||
315 | struct clk *tegra_clk_register_periph_gate(const char *name, | ||
316 | const char *parent_name, u8 gate_flags, void __iomem *clk_base, | ||
317 | unsigned long flags, int clk_num, | ||
318 | struct tegra_clk_periph_regs *pregs, int *enable_refcnt); | ||
319 | |||
320 | /** | ||
321 | * struct clk-periph - peripheral clock | ||
322 | * | ||
323 | * @magic: magic number to validate type | ||
324 | * @hw: handle between common and hardware-specific interfaces | ||
325 | * @mux: mux clock | ||
326 | * @divider: divider clock | ||
327 | * @gate: gate clock | ||
328 | * @mux_ops: mux clock ops | ||
329 | * @div_ops: divider clock ops | ||
330 | * @gate_ops: gate clock ops | ||
331 | */ | ||
332 | struct tegra_clk_periph { | ||
333 | u32 magic; | ||
334 | struct clk_hw hw; | ||
335 | struct clk_mux mux; | ||
336 | struct tegra_clk_frac_div divider; | ||
337 | struct tegra_clk_periph_gate gate; | ||
338 | |||
339 | const struct clk_ops *mux_ops; | ||
340 | const struct clk_ops *div_ops; | ||
341 | const struct clk_ops *gate_ops; | ||
342 | }; | ||
343 | |||
344 | #define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw) | ||
345 | |||
346 | #define TEGRA_CLK_PERIPH_MAGIC 0x18221223 | ||
347 | |||
348 | extern const struct clk_ops tegra_clk_periph_ops; | ||
349 | struct clk *tegra_clk_register_periph(const char *name, | ||
350 | const char **parent_names, int num_parents, | ||
351 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
352 | u32 offset); | ||
353 | struct clk *tegra_clk_register_periph_nodiv(const char *name, | ||
354 | const char **parent_names, int num_parents, | ||
355 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
356 | u32 offset); | ||
357 | |||
358 | #define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ | ||
359 | _div_shift, _div_width, _div_frac_width, \ | ||
360 | _div_flags, _clk_num, _enb_refcnt, _regs, \ | ||
361 | _gate_flags) \ | ||
362 | { \ | ||
363 | .mux = { \ | ||
364 | .flags = _mux_flags, \ | ||
365 | .shift = _mux_shift, \ | ||
366 | .width = _mux_width, \ | ||
367 | }, \ | ||
368 | .divider = { \ | ||
369 | .flags = _div_flags, \ | ||
370 | .shift = _div_shift, \ | ||
371 | .width = _div_width, \ | ||
372 | .frac_width = _div_frac_width, \ | ||
373 | }, \ | ||
374 | .gate = { \ | ||
375 | .flags = _gate_flags, \ | ||
376 | .clk_num = _clk_num, \ | ||
377 | .enable_refcnt = _enb_refcnt, \ | ||
378 | .regs = _regs, \ | ||
379 | }, \ | ||
380 | .mux_ops = &clk_mux_ops, \ | ||
381 | .div_ops = &tegra_clk_frac_div_ops, \ | ||
382 | .gate_ops = &tegra_clk_periph_gate_ops, \ | ||
383 | } | ||
384 | |||
385 | struct tegra_periph_init_data { | ||
386 | const char *name; | ||
387 | int clk_id; | ||
388 | const char **parent_names; | ||
389 | int num_parents; | ||
390 | struct tegra_clk_periph periph; | ||
391 | u32 offset; | ||
392 | const char *con_id; | ||
393 | const char *dev_id; | ||
394 | }; | ||
395 | |||
396 | #define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ | ||
397 | _mux_shift, _mux_width, _mux_flags, _div_shift, \ | ||
398 | _div_width, _div_frac_width, _div_flags, _regs, \ | ||
399 | _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ | ||
400 | { \ | ||
401 | .name = _name, \ | ||
402 | .clk_id = _clk_id, \ | ||
403 | .parent_names = _parent_names, \ | ||
404 | .num_parents = ARRAY_SIZE(_parent_names), \ | ||
405 | .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ | ||
406 | _mux_flags, _div_shift, \ | ||
407 | _div_width, _div_frac_width, \ | ||
408 | _div_flags, _clk_num, \ | ||
409 | _enb_refcnt, _regs, \ | ||
410 | _gate_flags), \ | ||
411 | .offset = _offset, \ | ||
412 | .con_id = _con_id, \ | ||
413 | .dev_id = _dev_id, \ | ||
414 | } | ||
415 | |||
416 | /** | ||
417 | * struct clk_super_mux - super clock | ||
418 | * | ||
419 | * @hw: handle between common and hardware-specific interfaces | ||
420 | * @reg: register controlling multiplexer | ||
421 | * @width: width of the multiplexer bit field | ||
422 | * @flags: hardware-specific flags | ||
423 | * @div2_index: bit controlling divide-by-2 | ||
424 | * @pllx_index: PLLX index in the parent list | ||
425 | * @lock: register lock | ||
426 | * | ||
427 | * Flags: | ||
428 | * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates | ||
429 | * that this is LP cluster clock. | ||
430 | */ | ||
431 | struct tegra_clk_super_mux { | ||
432 | struct clk_hw hw; | ||
433 | void __iomem *reg; | ||
434 | u8 width; | ||
435 | u8 flags; | ||
436 | u8 div2_index; | ||
437 | u8 pllx_index; | ||
438 | spinlock_t *lock; | ||
439 | }; | ||
440 | |||
441 | #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw) | ||
442 | |||
443 | #define TEGRA_DIVIDER_2 BIT(0) | ||
444 | |||
445 | extern const struct clk_ops tegra_clk_super_ops; | ||
446 | struct clk *tegra_clk_register_super_mux(const char *name, | ||
447 | const char **parent_names, u8 num_parents, | ||
448 | unsigned long flags, void __iomem *reg, u8 clk_super_flags, | ||
449 | u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock); | ||
450 | |||
451 | /** | ||
452 | * struct clk_init_tabel - clock initialization table | ||
453 | * @clk_id: clock id as mentioned in device tree bindings | ||
454 | * @parent_id: parent clock id as mentioned in device tree bindings | ||
455 | * @rate: rate to set | ||
456 | * @state: enable/disable | ||
457 | */ | ||
458 | struct tegra_clk_init_table { | ||
459 | unsigned int clk_id; | ||
460 | unsigned int parent_id; | ||
461 | unsigned long rate; | ||
462 | int state; | ||
463 | }; | ||
464 | |||
465 | /** | ||
466 | * struct clk_duplicate - duplicate clocks | ||
467 | * @clk_id: clock id as mentioned in device tree bindings | ||
468 | * @lookup: duplicate lookup entry for the clock | ||
469 | */ | ||
470 | struct tegra_clk_duplicate { | ||
471 | int clk_id; | ||
472 | struct clk_lookup lookup; | ||
473 | }; | ||
474 | |||
475 | #define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \ | ||
476 | { \ | ||
477 | .clk_id = _clk_id, \ | ||
478 | .lookup = { \ | ||
479 | .dev_id = _dev, \ | ||
480 | .con_id = _con, \ | ||
481 | }, \ | ||
482 | } | ||
483 | |||
484 | void tegra_init_from_table(struct tegra_clk_init_table *tbl, | ||
485 | struct clk *clks[], int clk_max); | ||
486 | |||
487 | void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, | ||
488 | struct clk *clks[], int clk_max); | ||
489 | |||
490 | #endif /* TEGRA_CLK_H */ | ||