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