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