Commit | Line | Data |
---|---|---|
c78275f3 | 1 | /* |
ceefc71d | 2 | * PTP 1588 clock for Freescale QorIQ 1588 timer |
c78275f3 RC |
3 | * |
4 | * Copyright (C) 2010 OMICRON electronics GmbH | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
375d6a1b JP |
20 | |
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
22 | ||
c78275f3 RC |
23 | #include <linux/device.h> |
24 | #include <linux/hrtimer.h> | |
c78275f3 RC |
25 | #include <linux/kernel.h> |
26 | #include <linux/module.h> | |
27 | #include <linux/of.h> | |
28 | #include <linux/of_platform.h> | |
29 | #include <linux/timex.h> | |
ceefc71d | 30 | #include <linux/slab.h> |
91305f28 | 31 | #include <linux/clk.h> |
c78275f3 | 32 | |
6c50c1ed | 33 | #include <linux/fsl/ptp_qoriq.h> |
ceefc71d | 34 | |
c78275f3 RC |
35 | /* |
36 | * Register access functions | |
37 | */ | |
38 | ||
1e562c81 YL |
39 | /* Caller must hold ptp_qoriq->lock. */ |
40 | static u64 tmr_cnt_read(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 41 | { |
1e562c81 | 42 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
43 | u64 ns; |
44 | u32 lo, hi; | |
45 | ||
a8f62d0c YL |
46 | lo = qoriq_read(®s->ctrl_regs->tmr_cnt_l); |
47 | hi = qoriq_read(®s->ctrl_regs->tmr_cnt_h); | |
c78275f3 RC |
48 | ns = ((u64) hi) << 32; |
49 | ns |= lo; | |
50 | return ns; | |
51 | } | |
52 | ||
1e562c81 YL |
53 | /* Caller must hold ptp_qoriq->lock. */ |
54 | static void tmr_cnt_write(struct ptp_qoriq *ptp_qoriq, u64 ns) | |
c78275f3 | 55 | { |
1e562c81 | 56 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
57 | u32 hi = ns >> 32; |
58 | u32 lo = ns & 0xffffffff; | |
59 | ||
a8f62d0c YL |
60 | qoriq_write(®s->ctrl_regs->tmr_cnt_l, lo); |
61 | qoriq_write(®s->ctrl_regs->tmr_cnt_h, hi); | |
c78275f3 RC |
62 | } |
63 | ||
1e562c81 YL |
64 | /* Caller must hold ptp_qoriq->lock. */ |
65 | static void set_alarm(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 66 | { |
1e562c81 | 67 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
68 | u64 ns; |
69 | u32 lo, hi; | |
70 | ||
1e562c81 | 71 | ns = tmr_cnt_read(ptp_qoriq) + 1500000000ULL; |
c78275f3 | 72 | ns = div_u64(ns, 1000000000UL) * 1000000000ULL; |
1e562c81 | 73 | ns -= ptp_qoriq->tclk_period; |
c78275f3 RC |
74 | hi = ns >> 32; |
75 | lo = ns & 0xffffffff; | |
a8f62d0c YL |
76 | qoriq_write(®s->alarm_regs->tmr_alarm1_l, lo); |
77 | qoriq_write(®s->alarm_regs->tmr_alarm1_h, hi); | |
c78275f3 RC |
78 | } |
79 | ||
1e562c81 YL |
80 | /* Caller must hold ptp_qoriq->lock. */ |
81 | static void set_fipers(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 82 | { |
1e562c81 | 83 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
a8f62d0c | 84 | |
1e562c81 YL |
85 | set_alarm(ptp_qoriq); |
86 | qoriq_write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1); | |
87 | qoriq_write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2); | |
c78275f3 RC |
88 | } |
89 | ||
1e562c81 | 90 | static int extts_clean_up(struct ptp_qoriq *ptp_qoriq, int index, |
6815d8b0 YL |
91 | bool update_event) |
92 | { | |
1e562c81 | 93 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
6815d8b0 YL |
94 | struct ptp_clock_event event; |
95 | void __iomem *reg_etts_l; | |
96 | void __iomem *reg_etts_h; | |
97 | u32 valid, stat, lo, hi; | |
98 | ||
99 | switch (index) { | |
100 | case 0: | |
101 | valid = ETS1_VLD; | |
102 | reg_etts_l = ®s->etts_regs->tmr_etts1_l; | |
103 | reg_etts_h = ®s->etts_regs->tmr_etts1_h; | |
104 | break; | |
105 | case 1: | |
106 | valid = ETS2_VLD; | |
107 | reg_etts_l = ®s->etts_regs->tmr_etts2_l; | |
108 | reg_etts_h = ®s->etts_regs->tmr_etts2_h; | |
109 | break; | |
110 | default: | |
111 | return -EINVAL; | |
112 | } | |
113 | ||
114 | event.type = PTP_CLOCK_EXTTS; | |
115 | event.index = index; | |
116 | ||
117 | do { | |
118 | lo = qoriq_read(reg_etts_l); | |
119 | hi = qoriq_read(reg_etts_h); | |
120 | ||
121 | if (update_event) { | |
122 | event.timestamp = ((u64) hi) << 32; | |
123 | event.timestamp |= lo; | |
1e562c81 | 124 | ptp_clock_event(ptp_qoriq->clock, &event); |
6815d8b0 YL |
125 | } |
126 | ||
127 | stat = qoriq_read(®s->ctrl_regs->tmr_stat); | |
1e562c81 | 128 | } while (ptp_qoriq->extts_fifo_support && (stat & valid)); |
6815d8b0 YL |
129 | |
130 | return 0; | |
131 | } | |
132 | ||
c78275f3 RC |
133 | /* |
134 | * Interrupt service routine | |
135 | */ | |
136 | ||
73356e4e | 137 | irqreturn_t ptp_qoriq_isr(int irq, void *priv) |
c78275f3 | 138 | { |
1e562c81 YL |
139 | struct ptp_qoriq *ptp_qoriq = priv; |
140 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 RC |
141 | struct ptp_clock_event event; |
142 | u64 ns; | |
b0bc10cc YL |
143 | u32 ack = 0, lo, hi, mask, val, irqs; |
144 | ||
1e562c81 | 145 | spin_lock(&ptp_qoriq->lock); |
c78275f3 | 146 | |
a8f62d0c | 147 | val = qoriq_read(®s->ctrl_regs->tmr_tevent); |
b0bc10cc YL |
148 | mask = qoriq_read(®s->ctrl_regs->tmr_temask); |
149 | ||
1e562c81 | 150 | spin_unlock(&ptp_qoriq->lock); |
b0bc10cc YL |
151 | |
152 | irqs = val & mask; | |
c78275f3 | 153 | |
b0bc10cc | 154 | if (irqs & ETS1) { |
c78275f3 | 155 | ack |= ETS1; |
1e562c81 | 156 | extts_clean_up(ptp_qoriq, 0, true); |
c78275f3 RC |
157 | } |
158 | ||
b0bc10cc | 159 | if (irqs & ETS2) { |
c78275f3 | 160 | ack |= ETS2; |
1e562c81 | 161 | extts_clean_up(ptp_qoriq, 1, true); |
c78275f3 RC |
162 | } |
163 | ||
b0bc10cc | 164 | if (irqs & ALM2) { |
c78275f3 | 165 | ack |= ALM2; |
1e562c81 | 166 | if (ptp_qoriq->alarm_value) { |
c78275f3 RC |
167 | event.type = PTP_CLOCK_ALARM; |
168 | event.index = 0; | |
1e562c81 YL |
169 | event.timestamp = ptp_qoriq->alarm_value; |
170 | ptp_clock_event(ptp_qoriq->clock, &event); | |
c78275f3 | 171 | } |
1e562c81 YL |
172 | if (ptp_qoriq->alarm_interval) { |
173 | ns = ptp_qoriq->alarm_value + ptp_qoriq->alarm_interval; | |
c78275f3 RC |
174 | hi = ns >> 32; |
175 | lo = ns & 0xffffffff; | |
a8f62d0c YL |
176 | qoriq_write(®s->alarm_regs->tmr_alarm2_l, lo); |
177 | qoriq_write(®s->alarm_regs->tmr_alarm2_h, hi); | |
1e562c81 | 178 | ptp_qoriq->alarm_value = ns; |
c78275f3 | 179 | } else { |
1e562c81 | 180 | spin_lock(&ptp_qoriq->lock); |
a8f62d0c | 181 | mask = qoriq_read(®s->ctrl_regs->tmr_temask); |
c78275f3 | 182 | mask &= ~ALM2EN; |
a8f62d0c | 183 | qoriq_write(®s->ctrl_regs->tmr_temask, mask); |
1e562c81 YL |
184 | spin_unlock(&ptp_qoriq->lock); |
185 | ptp_qoriq->alarm_value = 0; | |
186 | ptp_qoriq->alarm_interval = 0; | |
c78275f3 RC |
187 | } |
188 | } | |
189 | ||
b0bc10cc | 190 | if (irqs & PP1) { |
c78275f3 RC |
191 | ack |= PP1; |
192 | event.type = PTP_CLOCK_PPS; | |
1e562c81 | 193 | ptp_clock_event(ptp_qoriq->clock, &event); |
c78275f3 RC |
194 | } |
195 | ||
196 | if (ack) { | |
a8f62d0c | 197 | qoriq_write(®s->ctrl_regs->tmr_tevent, ack); |
c78275f3 RC |
198 | return IRQ_HANDLED; |
199 | } else | |
200 | return IRQ_NONE; | |
201 | } | |
73356e4e | 202 | EXPORT_SYMBOL_GPL(ptp_qoriq_isr); |
c78275f3 RC |
203 | |
204 | /* | |
205 | * PTP clock operations | |
206 | */ | |
207 | ||
73356e4e | 208 | int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) |
c78275f3 | 209 | { |
42895116 UDB |
210 | u64 adj, diff; |
211 | u32 tmr_add; | |
c78275f3 | 212 | int neg_adj = 0; |
1e562c81 YL |
213 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
214 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 | 215 | |
42895116 | 216 | if (scaled_ppm < 0) { |
c78275f3 | 217 | neg_adj = 1; |
42895116 | 218 | scaled_ppm = -scaled_ppm; |
c78275f3 | 219 | } |
1e562c81 | 220 | tmr_add = ptp_qoriq->tmr_add; |
c78275f3 | 221 | adj = tmr_add; |
42895116 UDB |
222 | |
223 | /* calculate diff as adj*(scaled_ppm/65536)/1000000 | |
224 | * and round() to the nearest integer | |
225 | */ | |
226 | adj *= scaled_ppm; | |
227 | diff = div_u64(adj, 8000000); | |
228 | diff = (diff >> 13) + ((diff >> 12) & 1); | |
c78275f3 RC |
229 | |
230 | tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; | |
231 | ||
a8f62d0c | 232 | qoriq_write(®s->ctrl_regs->tmr_add, tmr_add); |
c78275f3 RC |
233 | |
234 | return 0; | |
235 | } | |
73356e4e | 236 | EXPORT_SYMBOL_GPL(ptp_qoriq_adjfine); |
c78275f3 | 237 | |
73356e4e | 238 | int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta) |
c78275f3 RC |
239 | { |
240 | s64 now; | |
241 | unsigned long flags; | |
1e562c81 | 242 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
c78275f3 | 243 | |
1e562c81 | 244 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 245 | |
1e562c81 | 246 | now = tmr_cnt_read(ptp_qoriq); |
c78275f3 | 247 | now += delta; |
1e562c81 YL |
248 | tmr_cnt_write(ptp_qoriq, now); |
249 | set_fipers(ptp_qoriq); | |
c78275f3 | 250 | |
1e562c81 | 251 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 252 | |
c78275f3 RC |
253 | return 0; |
254 | } | |
73356e4e | 255 | EXPORT_SYMBOL_GPL(ptp_qoriq_adjtime); |
c78275f3 | 256 | |
73356e4e | 257 | int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) |
c78275f3 RC |
258 | { |
259 | u64 ns; | |
c78275f3 | 260 | unsigned long flags; |
1e562c81 | 261 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
c78275f3 | 262 | |
1e562c81 | 263 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 264 | |
1e562c81 | 265 | ns = tmr_cnt_read(ptp_qoriq); |
c78275f3 | 266 | |
1e562c81 | 267 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 268 | |
3359e7c2 RC |
269 | *ts = ns_to_timespec64(ns); |
270 | ||
c78275f3 RC |
271 | return 0; |
272 | } | |
73356e4e | 273 | EXPORT_SYMBOL_GPL(ptp_qoriq_gettime); |
c78275f3 | 274 | |
73356e4e YL |
275 | int ptp_qoriq_settime(struct ptp_clock_info *ptp, |
276 | const struct timespec64 *ts) | |
c78275f3 RC |
277 | { |
278 | u64 ns; | |
279 | unsigned long flags; | |
1e562c81 | 280 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
c78275f3 | 281 | |
3359e7c2 | 282 | ns = timespec64_to_ns(ts); |
c78275f3 | 283 | |
1e562c81 | 284 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 285 | |
1e562c81 YL |
286 | tmr_cnt_write(ptp_qoriq, ns); |
287 | set_fipers(ptp_qoriq); | |
c78275f3 | 288 | |
1e562c81 | 289 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 RC |
290 | |
291 | return 0; | |
292 | } | |
73356e4e | 293 | EXPORT_SYMBOL_GPL(ptp_qoriq_settime); |
c78275f3 | 294 | |
73356e4e YL |
295 | int ptp_qoriq_enable(struct ptp_clock_info *ptp, |
296 | struct ptp_clock_request *rq, int on) | |
c78275f3 | 297 | { |
1e562c81 YL |
298 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
299 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 | 300 | unsigned long flags; |
b0bc10cc | 301 | u32 bit, mask = 0; |
c78275f3 RC |
302 | |
303 | switch (rq->type) { | |
304 | case PTP_CLK_REQ_EXTTS: | |
305 | switch (rq->extts.index) { | |
306 | case 0: | |
307 | bit = ETS1EN; | |
308 | break; | |
309 | case 1: | |
310 | bit = ETS2EN; | |
311 | break; | |
312 | default: | |
313 | return -EINVAL; | |
314 | } | |
6815d8b0 YL |
315 | |
316 | if (on) | |
1e562c81 | 317 | extts_clean_up(ptp_qoriq, rq->extts.index, false); |
6815d8b0 | 318 | |
b0bc10cc | 319 | break; |
c78275f3 | 320 | case PTP_CLK_REQ_PPS: |
b0bc10cc | 321 | bit = PP1EN; |
c78275f3 | 322 | break; |
b0bc10cc YL |
323 | default: |
324 | return -EOPNOTSUPP; | |
325 | } | |
326 | ||
1e562c81 | 327 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
b0bc10cc YL |
328 | |
329 | mask = qoriq_read(®s->ctrl_regs->tmr_temask); | |
330 | if (on) { | |
331 | mask |= bit; | |
332 | qoriq_write(®s->ctrl_regs->tmr_tevent, bit); | |
333 | } else { | |
334 | mask &= ~bit; | |
c78275f3 RC |
335 | } |
336 | ||
b0bc10cc YL |
337 | qoriq_write(®s->ctrl_regs->tmr_temask, mask); |
338 | ||
1e562c81 | 339 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
b0bc10cc | 340 | return 0; |
c78275f3 | 341 | } |
73356e4e | 342 | EXPORT_SYMBOL_GPL(ptp_qoriq_enable); |
c78275f3 | 343 | |
ceefc71d | 344 | static const struct ptp_clock_info ptp_qoriq_caps = { |
c78275f3 | 345 | .owner = THIS_MODULE, |
ceefc71d | 346 | .name = "qoriq ptp clock", |
c78275f3 | 347 | .max_adj = 512000, |
cd4baaaa | 348 | .n_alarm = 0, |
c78275f3 RC |
349 | .n_ext_ts = N_EXT_TS, |
350 | .n_per_out = 0, | |
4986b4f0 | 351 | .n_pins = 0, |
c78275f3 | 352 | .pps = 1, |
ceefc71d YL |
353 | .adjfine = ptp_qoriq_adjfine, |
354 | .adjtime = ptp_qoriq_adjtime, | |
355 | .gettime64 = ptp_qoriq_gettime, | |
356 | .settime64 = ptp_qoriq_settime, | |
357 | .enable = ptp_qoriq_enable, | |
c78275f3 RC |
358 | }; |
359 | ||
91305f28 | 360 | /** |
1e562c81 | 361 | * ptp_qoriq_nominal_freq - calculate nominal frequency according to |
91305f28 YL |
362 | * reference clock frequency |
363 | * | |
364 | * @clk_src: reference clock frequency | |
365 | * | |
366 | * The nominal frequency is the desired clock frequency. | |
367 | * It should be less than the reference clock frequency. | |
368 | * It should be a factor of 1000MHz. | |
369 | * | |
370 | * Return the nominal frequency | |
371 | */ | |
1e562c81 | 372 | static u32 ptp_qoriq_nominal_freq(u32 clk_src) |
91305f28 YL |
373 | { |
374 | u32 remainder = 0; | |
375 | ||
376 | clk_src /= 1000000; | |
377 | remainder = clk_src % 100; | |
378 | if (remainder) { | |
379 | clk_src -= remainder; | |
380 | clk_src += 100; | |
381 | } | |
382 | ||
383 | do { | |
384 | clk_src -= 100; | |
385 | ||
386 | } while (1000 % clk_src); | |
387 | ||
388 | return clk_src * 1000000; | |
389 | } | |
390 | ||
391 | /** | |
1e562c81 | 392 | * ptp_qoriq_auto_config - calculate a set of default configurations |
91305f28 | 393 | * |
1e562c81 | 394 | * @ptp_qoriq: pointer to ptp_qoriq |
91305f28 YL |
395 | * @node: pointer to device_node |
396 | * | |
397 | * If below dts properties are not provided, this function will be | |
398 | * called to calculate a set of default configurations for them. | |
399 | * "fsl,tclk-period" | |
400 | * "fsl,tmr-prsc" | |
401 | * "fsl,tmr-add" | |
402 | * "fsl,tmr-fiper1" | |
403 | * "fsl,tmr-fiper2" | |
404 | * "fsl,max-adj" | |
405 | * | |
406 | * Return 0 if success | |
407 | */ | |
1e562c81 | 408 | static int ptp_qoriq_auto_config(struct ptp_qoriq *ptp_qoriq, |
91305f28 YL |
409 | struct device_node *node) |
410 | { | |
411 | struct clk *clk; | |
412 | u64 freq_comp; | |
413 | u64 max_adj; | |
414 | u32 nominal_freq; | |
74c05a33 | 415 | u32 remainder = 0; |
91305f28 YL |
416 | u32 clk_src = 0; |
417 | ||
1e562c81 | 418 | ptp_qoriq->cksel = DEFAULT_CKSEL; |
91305f28 YL |
419 | |
420 | clk = of_clk_get(node, 0); | |
421 | if (!IS_ERR(clk)) { | |
422 | clk_src = clk_get_rate(clk); | |
423 | clk_put(clk); | |
424 | } | |
425 | ||
426 | if (clk_src <= 100000000UL) { | |
427 | pr_err("error reference clock value, or lower than 100MHz\n"); | |
428 | return -EINVAL; | |
429 | } | |
430 | ||
1e562c81 | 431 | nominal_freq = ptp_qoriq_nominal_freq(clk_src); |
91305f28 YL |
432 | if (!nominal_freq) |
433 | return -EINVAL; | |
434 | ||
1e562c81 YL |
435 | ptp_qoriq->tclk_period = 1000000000UL / nominal_freq; |
436 | ptp_qoriq->tmr_prsc = DEFAULT_TMR_PRSC; | |
91305f28 YL |
437 | |
438 | /* Calculate initial frequency compensation value for TMR_ADD register. | |
439 | * freq_comp = ceil(2^32 / freq_ratio) | |
440 | * freq_ratio = reference_clock_freq / nominal_freq | |
441 | */ | |
442 | freq_comp = ((u64)1 << 32) * nominal_freq; | |
74c05a33 YL |
443 | freq_comp = div_u64_rem(freq_comp, clk_src, &remainder); |
444 | if (remainder) | |
91305f28 YL |
445 | freq_comp++; |
446 | ||
1e562c81 YL |
447 | ptp_qoriq->tmr_add = freq_comp; |
448 | ptp_qoriq->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq->tclk_period; | |
449 | ptp_qoriq->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq->tclk_period; | |
91305f28 YL |
450 | |
451 | /* max_adj = 1000000000 * (freq_ratio - 1.0) - 1 | |
452 | * freq_ratio = reference_clock_freq / nominal_freq | |
453 | */ | |
454 | max_adj = 1000000000ULL * (clk_src - nominal_freq); | |
74c05a33 | 455 | max_adj = div_u64(max_adj, nominal_freq) - 1; |
1e562c81 | 456 | ptp_qoriq->caps.max_adj = max_adj; |
91305f28 YL |
457 | |
458 | return 0; | |
459 | } | |
460 | ||
ff54571a YL |
461 | int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base, |
462 | const struct ptp_clock_info caps) | |
c78275f3 | 463 | { |
ff54571a | 464 | struct device_node *node = ptp_qoriq->dev->of_node; |
1e562c81 | 465 | struct ptp_qoriq_registers *regs; |
d28fdf0f | 466 | struct timespec64 now; |
c78275f3 | 467 | unsigned long flags; |
ff54571a | 468 | u32 tmr_ctrl; |
c78275f3 | 469 | |
ff54571a YL |
470 | ptp_qoriq->base = base; |
471 | ptp_qoriq->caps = caps; | |
e58f6f4f | 472 | |
1e562c81 YL |
473 | if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel)) |
474 | ptp_qoriq->cksel = DEFAULT_CKSEL; | |
c78275f3 | 475 | |
6815d8b0 | 476 | if (of_property_read_bool(node, "fsl,extts-fifo")) |
1e562c81 | 477 | ptp_qoriq->extts_fifo_support = true; |
6815d8b0 | 478 | else |
1e562c81 | 479 | ptp_qoriq->extts_fifo_support = false; |
6815d8b0 | 480 | |
c35ec779 | 481 | if (of_property_read_u32(node, |
1e562c81 | 482 | "fsl,tclk-period", &ptp_qoriq->tclk_period) || |
c35ec779 | 483 | of_property_read_u32(node, |
1e562c81 | 484 | "fsl,tmr-prsc", &ptp_qoriq->tmr_prsc) || |
c35ec779 | 485 | of_property_read_u32(node, |
1e562c81 | 486 | "fsl,tmr-add", &ptp_qoriq->tmr_add) || |
c35ec779 | 487 | of_property_read_u32(node, |
1e562c81 | 488 | "fsl,tmr-fiper1", &ptp_qoriq->tmr_fiper1) || |
c35ec779 | 489 | of_property_read_u32(node, |
1e562c81 | 490 | "fsl,tmr-fiper2", &ptp_qoriq->tmr_fiper2) || |
c35ec779 | 491 | of_property_read_u32(node, |
1e562c81 | 492 | "fsl,max-adj", &ptp_qoriq->caps.max_adj)) { |
91305f28 YL |
493 | pr_warn("device tree node missing required elements, try automatic configuration\n"); |
494 | ||
1e562c81 | 495 | if (ptp_qoriq_auto_config(ptp_qoriq, node)) |
ff54571a | 496 | return -ENODEV; |
c78275f3 RC |
497 | } |
498 | ||
a8f62d0c | 499 | if (of_device_is_compatible(node, "fsl,fman-ptp-timer")) { |
1e562c81 YL |
500 | ptp_qoriq->regs.ctrl_regs = base + FMAN_CTRL_REGS_OFFSET; |
501 | ptp_qoriq->regs.alarm_regs = base + FMAN_ALARM_REGS_OFFSET; | |
502 | ptp_qoriq->regs.fiper_regs = base + FMAN_FIPER_REGS_OFFSET; | |
503 | ptp_qoriq->regs.etts_regs = base + FMAN_ETTS_REGS_OFFSET; | |
a8f62d0c | 504 | } else { |
1e562c81 YL |
505 | ptp_qoriq->regs.ctrl_regs = base + CTRL_REGS_OFFSET; |
506 | ptp_qoriq->regs.alarm_regs = base + ALARM_REGS_OFFSET; | |
507 | ptp_qoriq->regs.fiper_regs = base + FIPER_REGS_OFFSET; | |
508 | ptp_qoriq->regs.etts_regs = base + ETTS_REGS_OFFSET; | |
a8f62d0c YL |
509 | } |
510 | ||
f696a21c | 511 | ktime_get_real_ts64(&now); |
1e562c81 | 512 | ptp_qoriq_settime(&ptp_qoriq->caps, &now); |
c78275f3 RC |
513 | |
514 | tmr_ctrl = | |
1e562c81 YL |
515 | (ptp_qoriq->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT | |
516 | (ptp_qoriq->cksel & CKSEL_MASK) << CKSEL_SHIFT; | |
c78275f3 | 517 | |
ff54571a | 518 | spin_lock_init(&ptp_qoriq->lock); |
1e562c81 | 519 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 520 | |
1e562c81 | 521 | regs = &ptp_qoriq->regs; |
a8f62d0c | 522 | qoriq_write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl); |
1e562c81 YL |
523 | qoriq_write(®s->ctrl_regs->tmr_add, ptp_qoriq->tmr_add); |
524 | qoriq_write(®s->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc); | |
525 | qoriq_write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1); | |
526 | qoriq_write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2); | |
527 | set_alarm(ptp_qoriq); | |
a8f62d0c | 528 | qoriq_write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl|FIPERST|RTPE|TE|FRD); |
c78275f3 | 529 | |
1e562c81 | 530 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 531 | |
ff54571a YL |
532 | ptp_qoriq->clock = ptp_clock_register(&ptp_qoriq->caps, ptp_qoriq->dev); |
533 | if (IS_ERR(ptp_qoriq->clock)) | |
534 | return PTR_ERR(ptp_qoriq->clock); | |
c78275f3 | 535 | |
ff54571a | 536 | ptp_qoriq->phc_index = ptp_clock_index(ptp_qoriq->clock); |
1e562c81 | 537 | ptp_qoriq_create_debugfs(ptp_qoriq); |
ff54571a YL |
538 | return 0; |
539 | } | |
540 | EXPORT_SYMBOL_GPL(ptp_qoriq_init); | |
541 | ||
542 | void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq) | |
543 | { | |
544 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
545 | ||
546 | qoriq_write(®s->ctrl_regs->tmr_temask, 0); | |
547 | qoriq_write(®s->ctrl_regs->tmr_ctrl, 0); | |
548 | ||
549 | ptp_qoriq_remove_debugfs(ptp_qoriq); | |
550 | ptp_clock_unregister(ptp_qoriq->clock); | |
551 | iounmap(ptp_qoriq->base); | |
552 | free_irq(ptp_qoriq->irq, ptp_qoriq); | |
553 | } | |
554 | EXPORT_SYMBOL_GPL(ptp_qoriq_free); | |
555 | ||
556 | static int ptp_qoriq_probe(struct platform_device *dev) | |
557 | { | |
558 | struct ptp_qoriq *ptp_qoriq; | |
559 | int err = -ENOMEM; | |
560 | void __iomem *base; | |
c78275f3 | 561 | |
ff54571a YL |
562 | ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL); |
563 | if (!ptp_qoriq) | |
564 | goto no_memory; | |
565 | ||
566 | ptp_qoriq->dev = &dev->dev; | |
567 | ||
568 | err = -ENODEV; | |
569 | ||
570 | ptp_qoriq->irq = platform_get_irq(dev, 0); | |
571 | if (ptp_qoriq->irq < 0) { | |
572 | pr_err("irq not in device tree\n"); | |
573 | goto no_node; | |
574 | } | |
575 | if (request_irq(ptp_qoriq->irq, ptp_qoriq_isr, IRQF_SHARED, | |
576 | DRIVER, ptp_qoriq)) { | |
577 | pr_err("request_irq failed\n"); | |
578 | goto no_node; | |
579 | } | |
580 | ||
581 | ptp_qoriq->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
582 | if (!ptp_qoriq->rsrc) { | |
583 | pr_err("no resource\n"); | |
584 | goto no_resource; | |
585 | } | |
586 | if (request_resource(&iomem_resource, ptp_qoriq->rsrc)) { | |
587 | pr_err("resource busy\n"); | |
588 | goto no_resource; | |
589 | } | |
590 | ||
591 | base = ioremap(ptp_qoriq->rsrc->start, | |
592 | resource_size(ptp_qoriq->rsrc)); | |
593 | if (!base) { | |
594 | pr_err("ioremap ptp registers failed\n"); | |
595 | goto no_ioremap; | |
596 | } | |
597 | ||
598 | err = ptp_qoriq_init(ptp_qoriq, base, ptp_qoriq_caps); | |
599 | if (err) | |
600 | goto no_clock; | |
601 | ||
602 | platform_set_drvdata(dev, ptp_qoriq); | |
c78275f3 RC |
603 | return 0; |
604 | ||
605 | no_clock: | |
1e562c81 | 606 | iounmap(ptp_qoriq->base); |
c78275f3 | 607 | no_ioremap: |
1e562c81 | 608 | release_resource(ptp_qoriq->rsrc); |
c78275f3 | 609 | no_resource: |
1e562c81 | 610 | free_irq(ptp_qoriq->irq, ptp_qoriq); |
c78275f3 | 611 | no_node: |
1e562c81 | 612 | kfree(ptp_qoriq); |
c78275f3 RC |
613 | no_memory: |
614 | return err; | |
615 | } | |
616 | ||
1e562c81 | 617 | static int ptp_qoriq_remove(struct platform_device *dev) |
c78275f3 | 618 | { |
1e562c81 | 619 | struct ptp_qoriq *ptp_qoriq = platform_get_drvdata(dev); |
c78275f3 | 620 | |
ff54571a | 621 | ptp_qoriq_free(ptp_qoriq); |
1e562c81 | 622 | release_resource(ptp_qoriq->rsrc); |
1e562c81 | 623 | kfree(ptp_qoriq); |
c78275f3 RC |
624 | return 0; |
625 | } | |
626 | ||
94e5a2a8 | 627 | static const struct of_device_id match_table[] = { |
c78275f3 | 628 | { .compatible = "fsl,etsec-ptp" }, |
a8f62d0c | 629 | { .compatible = "fsl,fman-ptp-timer" }, |
c78275f3 RC |
630 | {}, |
631 | }; | |
23860063 | 632 | MODULE_DEVICE_TABLE(of, match_table); |
c78275f3 | 633 | |
1e562c81 | 634 | static struct platform_driver ptp_qoriq_driver = { |
c78275f3 | 635 | .driver = { |
ceefc71d | 636 | .name = "ptp_qoriq", |
c78275f3 | 637 | .of_match_table = match_table, |
c78275f3 | 638 | }, |
1e562c81 YL |
639 | .probe = ptp_qoriq_probe, |
640 | .remove = ptp_qoriq_remove, | |
c78275f3 RC |
641 | }; |
642 | ||
1e562c81 | 643 | module_platform_driver(ptp_qoriq_driver); |
c78275f3 | 644 | |
c2ec3ff6 | 645 | MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>"); |
ceefc71d | 646 | MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer"); |
c78275f3 | 647 | MODULE_LICENSE("GPL"); |