Commit | Line | Data |
---|---|---|
38d34c31 BB |
1 | /* |
2 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/clkdev.h> | |
13 | #include <linux/clk/at91_pmc.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/of.h> | |
16 | #include <linux/of_address.h> | |
17 | #include <linux/of_irq.h> | |
18 | #include <linux/io.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/irq.h> | |
21 | #include <linux/sched.h> | |
22 | #include <linux/wait.h> | |
23 | ||
24 | #include "pmc.h" | |
25 | ||
26 | #define SLOW_CLOCK_FREQ 32768 | |
27 | #define MAINF_DIV 16 | |
28 | #define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \ | |
29 | SLOW_CLOCK_FREQ) | |
30 | #define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ) | |
31 | #define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT | |
32 | ||
33 | struct clk_main { | |
34 | struct clk_hw hw; | |
35 | struct at91_pmc *pmc; | |
36 | unsigned long rate; | |
37 | unsigned int irq; | |
38 | wait_queue_head_t wait; | |
39 | }; | |
40 | ||
41 | #define to_clk_main(hw) container_of(hw, struct clk_main, hw) | |
42 | ||
43 | static irqreturn_t clk_main_irq_handler(int irq, void *dev_id) | |
44 | { | |
45 | struct clk_main *clkmain = (struct clk_main *)dev_id; | |
46 | ||
47 | wake_up(&clkmain->wait); | |
48 | disable_irq_nosync(clkmain->irq); | |
49 | ||
50 | return IRQ_HANDLED; | |
51 | } | |
52 | ||
53 | static int clk_main_prepare(struct clk_hw *hw) | |
54 | { | |
55 | struct clk_main *clkmain = to_clk_main(hw); | |
56 | struct at91_pmc *pmc = clkmain->pmc; | |
57 | unsigned long halt_time, timeout; | |
58 | u32 tmp; | |
59 | ||
60 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) { | |
61 | enable_irq(clkmain->irq); | |
62 | wait_event(clkmain->wait, | |
63 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); | |
64 | } | |
65 | ||
66 | if (clkmain->rate) | |
67 | return 0; | |
68 | ||
69 | timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); | |
70 | do { | |
71 | halt_time = jiffies; | |
72 | tmp = pmc_read(pmc, AT91_CKGR_MCFR); | |
73 | if (tmp & AT91_PMC_MAINRDY) | |
74 | return 0; | |
75 | usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); | |
76 | } while (time_before(halt_time, timeout)); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | static int clk_main_is_prepared(struct clk_hw *hw) | |
82 | { | |
83 | struct clk_main *clkmain = to_clk_main(hw); | |
84 | ||
85 | return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); | |
86 | } | |
87 | ||
88 | static unsigned long clk_main_recalc_rate(struct clk_hw *hw, | |
89 | unsigned long parent_rate) | |
90 | { | |
91 | u32 tmp; | |
92 | struct clk_main *clkmain = to_clk_main(hw); | |
93 | struct at91_pmc *pmc = clkmain->pmc; | |
94 | ||
95 | if (clkmain->rate) | |
96 | return clkmain->rate; | |
97 | ||
98 | tmp = pmc_read(pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINF; | |
99 | clkmain->rate = (tmp * parent_rate) / MAINF_DIV; | |
100 | ||
101 | return clkmain->rate; | |
102 | } | |
103 | ||
104 | static const struct clk_ops main_ops = { | |
105 | .prepare = clk_main_prepare, | |
106 | .is_prepared = clk_main_is_prepared, | |
107 | .recalc_rate = clk_main_recalc_rate, | |
108 | }; | |
109 | ||
110 | static struct clk * __init | |
111 | at91_clk_register_main(struct at91_pmc *pmc, | |
112 | unsigned int irq, | |
113 | const char *name, | |
114 | const char *parent_name, | |
115 | unsigned long rate) | |
116 | { | |
117 | int ret; | |
118 | struct clk_main *clkmain; | |
119 | struct clk *clk = NULL; | |
120 | struct clk_init_data init; | |
121 | ||
122 | if (!pmc || !irq || !name) | |
123 | return ERR_PTR(-EINVAL); | |
124 | ||
125 | if (!rate && !parent_name) | |
126 | return ERR_PTR(-EINVAL); | |
127 | ||
128 | clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); | |
129 | if (!clkmain) | |
130 | return ERR_PTR(-ENOMEM); | |
131 | ||
132 | init.name = name; | |
133 | init.ops = &main_ops; | |
134 | init.parent_names = parent_name ? &parent_name : NULL; | |
135 | init.num_parents = parent_name ? 1 : 0; | |
136 | init.flags = parent_name ? 0 : CLK_IS_ROOT; | |
137 | ||
138 | clkmain->hw.init = &init; | |
139 | clkmain->rate = rate; | |
140 | clkmain->pmc = pmc; | |
141 | clkmain->irq = irq; | |
142 | init_waitqueue_head(&clkmain->wait); | |
143 | irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); | |
144 | ret = request_irq(clkmain->irq, clk_main_irq_handler, | |
145 | IRQF_TRIGGER_HIGH, "clk-main", clkmain); | |
146 | if (ret) | |
147 | return ERR_PTR(ret); | |
148 | ||
149 | clk = clk_register(NULL, &clkmain->hw); | |
150 | if (IS_ERR(clk)) { | |
151 | free_irq(clkmain->irq, clkmain); | |
152 | kfree(clkmain); | |
153 | } | |
154 | ||
155 | return clk; | |
156 | } | |
157 | ||
158 | ||
159 | ||
160 | static void __init | |
161 | of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc) | |
162 | { | |
163 | struct clk *clk; | |
164 | unsigned int irq; | |
165 | const char *parent_name; | |
166 | const char *name = np->name; | |
167 | u32 rate = 0; | |
168 | ||
169 | parent_name = of_clk_get_parent_name(np, 0); | |
170 | of_property_read_string(np, "clock-output-names", &name); | |
171 | of_property_read_u32(np, "clock-frequency", &rate); | |
172 | irq = irq_of_parse_and_map(np, 0); | |
173 | if (!irq) | |
174 | return; | |
175 | ||
176 | clk = at91_clk_register_main(pmc, irq, name, parent_name, rate); | |
177 | if (IS_ERR(clk)) | |
178 | return; | |
179 | ||
180 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | |
181 | } | |
182 | ||
183 | void __init of_at91rm9200_clk_main_setup(struct device_node *np, | |
184 | struct at91_pmc *pmc) | |
185 | { | |
186 | of_at91_clk_main_setup(np, pmc); | |
187 | } |