2 * Copyright 2017 Broadcom
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <linux/err.h>
16 #include <linux/module.h>
17 #include <linux/mod_devicetable.h>
18 #include <linux/platform_device.h>
19 #include <linux/ptp_clock_kernel.h>
20 #include <linux/types.h>
22 #define DTE_NCO_LOW_TIME_REG 0x00
23 #define DTE_NCO_TIME_REG 0x04
24 #define DTE_NCO_OVERFLOW_REG 0x08
25 #define DTE_NCO_INC_REG 0x0c
27 #define DTE_NCO_SUM2_MASK 0xffffffff
28 #define DTE_NCO_SUM2_SHIFT 4ULL
30 #define DTE_NCO_SUM3_MASK 0xff
31 #define DTE_NCO_SUM3_SHIFT 36ULL
32 #define DTE_NCO_SUM3_WR_SHIFT 8
34 #define DTE_NCO_TS_WRAP_MASK 0xfff
35 #define DTE_NCO_TS_WRAP_LSHIFT 32
37 #define DTE_NCO_INC_DEFAULT 0x80000000
38 #define DTE_NUM_REGS_TO_RESTORE 4
40 /* Full wrap around is 44bits in ns (~4.887 hrs) */
41 #define DTE_WRAP_AROUND_NSEC_SHIFT 44
44 #define DTE_NCO_MAX_NS 0xFFFFFFFFFFFLL
46 /* 125MHz with 3.29 reg cfg */
47 #define DTE_PPB_ADJ(ppb) (u32)(div64_u64((((u64)abs(ppb) * BIT(28)) +\
48 62500000ULL), 125000000ULL))
50 /* ptp dte priv structure */
53 struct ptp_clock
*ptp_clk
;
54 struct ptp_clock_info caps
;
59 u32 reg_val
[DTE_NUM_REGS_TO_RESTORE
];
62 static void dte_write_nco(void __iomem
*regs
, s64 ns
)
66 sum2
= (u32
)((ns
>> DTE_NCO_SUM2_SHIFT
) & DTE_NCO_SUM2_MASK
);
67 /* compensate for ignoring sum1 */
68 if (sum2
!= DTE_NCO_SUM2_MASK
)
71 /* to write sum3, bits [15:8] needs to be written */
72 sum3
= (u32
)(((ns
>> DTE_NCO_SUM3_SHIFT
) & DTE_NCO_SUM3_MASK
) <<
73 DTE_NCO_SUM3_WR_SHIFT
);
75 writel(0, (regs
+ DTE_NCO_LOW_TIME_REG
));
76 writel(sum2
, (regs
+ DTE_NCO_TIME_REG
));
77 writel(sum3
, (regs
+ DTE_NCO_OVERFLOW_REG
));
80 static s64
dte_read_nco(void __iomem
*regs
)
86 * ignoring sum1 (4 bits) gives a 16ns resolution, which
87 * works due to the async register read.
89 sum3
= readl(regs
+ DTE_NCO_OVERFLOW_REG
) & DTE_NCO_SUM3_MASK
;
90 sum2
= readl(regs
+ DTE_NCO_TIME_REG
);
91 ns
= ((s64
)sum3
<< DTE_NCO_SUM3_SHIFT
) |
92 ((s64
)sum2
<< DTE_NCO_SUM2_SHIFT
);
97 static void dte_write_nco_delta(struct ptp_dte
*ptp_dte
, s64 delta
)
101 ns
= dte_read_nco(ptp_dte
->regs
);
103 /* handle wraparound conditions */
104 if ((delta
< 0) && (abs(delta
) > ns
)) {
105 if (ptp_dte
->ts_wrap_cnt
) {
106 ns
+= DTE_NCO_MAX_NS
+ delta
;
107 ptp_dte
->ts_wrap_cnt
--;
113 if (ns
> DTE_NCO_MAX_NS
) {
114 ptp_dte
->ts_wrap_cnt
++;
115 ns
-= DTE_NCO_MAX_NS
;
119 dte_write_nco(ptp_dte
->regs
, ns
);
121 ptp_dte
->ts_ovf_last
= (ns
>> DTE_NCO_TS_WRAP_LSHIFT
) &
122 DTE_NCO_TS_WRAP_MASK
;
125 static s64
dte_read_nco_with_ovf(struct ptp_dte
*ptp_dte
)
130 ns
= dte_read_nco(ptp_dte
->regs
);
132 /*Timestamp overflow: 8 LSB bits of sum3, 4 MSB bits of sum2 */
133 ts_ovf
= (ns
>> DTE_NCO_TS_WRAP_LSHIFT
) & DTE_NCO_TS_WRAP_MASK
;
135 /* Check for wrap around */
136 if (ts_ovf
< ptp_dte
->ts_ovf_last
)
137 ptp_dte
->ts_wrap_cnt
++;
139 ptp_dte
->ts_ovf_last
= ts_ovf
;
141 /* adjust for wraparounds */
142 ns
+= (s64
)(BIT_ULL(DTE_WRAP_AROUND_NSEC_SHIFT
) * ptp_dte
->ts_wrap_cnt
);
147 static int ptp_dte_adjfreq(struct ptp_clock_info
*ptp
, s32 ppb
)
151 struct ptp_dte
*ptp_dte
= container_of(ptp
, struct ptp_dte
, caps
);
153 if (abs(ppb
) > ptp_dte
->caps
.max_adj
) {
154 dev_err(ptp_dte
->dev
, "ppb adj too big\n");
159 nco_incr
= DTE_NCO_INC_DEFAULT
- DTE_PPB_ADJ(ppb
);
161 nco_incr
= DTE_NCO_INC_DEFAULT
+ DTE_PPB_ADJ(ppb
);
163 spin_lock_irqsave(&ptp_dte
->lock
, flags
);
164 writel(nco_incr
, ptp_dte
->regs
+ DTE_NCO_INC_REG
);
165 spin_unlock_irqrestore(&ptp_dte
->lock
, flags
);
170 static int ptp_dte_adjtime(struct ptp_clock_info
*ptp
, s64 delta
)
173 struct ptp_dte
*ptp_dte
= container_of(ptp
, struct ptp_dte
, caps
);
175 spin_lock_irqsave(&ptp_dte
->lock
, flags
);
176 dte_write_nco_delta(ptp_dte
, delta
);
177 spin_unlock_irqrestore(&ptp_dte
->lock
, flags
);
182 static int ptp_dte_gettime(struct ptp_clock_info
*ptp
, struct timespec64
*ts
)
185 struct ptp_dte
*ptp_dte
= container_of(ptp
, struct ptp_dte
, caps
);
187 spin_lock_irqsave(&ptp_dte
->lock
, flags
);
188 *ts
= ns_to_timespec64(dte_read_nco_with_ovf(ptp_dte
));
189 spin_unlock_irqrestore(&ptp_dte
->lock
, flags
);
194 static int ptp_dte_settime(struct ptp_clock_info
*ptp
,
195 const struct timespec64
*ts
)
198 struct ptp_dte
*ptp_dte
= container_of(ptp
, struct ptp_dte
, caps
);
200 spin_lock_irqsave(&ptp_dte
->lock
, flags
);
202 /* Disable nco increment */
203 writel(0, ptp_dte
->regs
+ DTE_NCO_INC_REG
);
205 dte_write_nco(ptp_dte
->regs
, timespec64_to_ns(ts
));
207 /* reset overflow and wrap counter */
208 ptp_dte
->ts_ovf_last
= 0;
209 ptp_dte
->ts_wrap_cnt
= 0;
211 /* Enable nco increment */
212 writel(DTE_NCO_INC_DEFAULT
, ptp_dte
->regs
+ DTE_NCO_INC_REG
);
214 spin_unlock_irqrestore(&ptp_dte
->lock
, flags
);
219 static int ptp_dte_enable(struct ptp_clock_info
*ptp
,
220 struct ptp_clock_request
*rq
, int on
)
225 static const struct ptp_clock_info ptp_dte_caps
= {
226 .owner
= THIS_MODULE
,
227 .name
= "DTE PTP timer",
232 .adjfreq
= ptp_dte_adjfreq
,
233 .adjtime
= ptp_dte_adjtime
,
234 .gettime64
= ptp_dte_gettime
,
235 .settime64
= ptp_dte_settime
,
236 .enable
= ptp_dte_enable
,
239 static int ptp_dte_probe(struct platform_device
*pdev
)
241 struct ptp_dte
*ptp_dte
;
242 struct device
*dev
= &pdev
->dev
;
243 struct resource
*res
;
245 ptp_dte
= devm_kzalloc(dev
, sizeof(struct ptp_dte
), GFP_KERNEL
);
249 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
250 ptp_dte
->regs
= devm_ioremap_resource(dev
, res
);
251 if (IS_ERR(ptp_dte
->regs
)) {
253 "%s: io remap failed\n", __func__
);
254 return PTR_ERR(ptp_dte
->regs
);
257 spin_lock_init(&ptp_dte
->lock
);
260 ptp_dte
->caps
= ptp_dte_caps
;
261 ptp_dte
->ptp_clk
= ptp_clock_register(&ptp_dte
->caps
, &pdev
->dev
);
262 if (IS_ERR(ptp_dte
->ptp_clk
)) {
264 "%s: Failed to register ptp clock\n", __func__
);
265 return PTR_ERR(ptp_dte
->ptp_clk
);
268 platform_set_drvdata(pdev
, ptp_dte
);
270 dev_info(dev
, "ptp clk probe done\n");
275 static int ptp_dte_remove(struct platform_device
*pdev
)
277 struct ptp_dte
*ptp_dte
= platform_get_drvdata(pdev
);
280 ptp_clock_unregister(ptp_dte
->ptp_clk
);
282 for (i
= 0; i
< DTE_NUM_REGS_TO_RESTORE
; i
++)
283 writel(0, ptp_dte
->regs
+ (i
* sizeof(u32
)));
288 #ifdef CONFIG_PM_SLEEP
289 static int ptp_dte_suspend(struct device
*dev
)
291 struct platform_device
*pdev
= to_platform_device(dev
);
292 struct ptp_dte
*ptp_dte
= platform_get_drvdata(pdev
);
295 for (i
= 0; i
< DTE_NUM_REGS_TO_RESTORE
; i
++) {
296 ptp_dte
->reg_val
[i
] =
297 readl(ptp_dte
->regs
+ (i
* sizeof(u32
)));
300 /* disable the nco */
301 writel(0, ptp_dte
->regs
+ DTE_NCO_INC_REG
);
306 static int ptp_dte_resume(struct device
*dev
)
308 struct platform_device
*pdev
= to_platform_device(dev
);
309 struct ptp_dte
*ptp_dte
= platform_get_drvdata(pdev
);
312 for (i
= 0; i
< DTE_NUM_REGS_TO_RESTORE
; i
++) {
313 if ((i
* sizeof(u32
)) != DTE_NCO_OVERFLOW_REG
)
314 writel(ptp_dte
->reg_val
[i
],
315 (ptp_dte
->regs
+ (i
* sizeof(u32
))));
317 writel(((ptp_dte
->reg_val
[i
] &
318 DTE_NCO_SUM3_MASK
) << DTE_NCO_SUM3_WR_SHIFT
),
319 (ptp_dte
->regs
+ (i
* sizeof(u32
))));
325 static const struct dev_pm_ops ptp_dte_pm_ops
= {
326 .suspend
= ptp_dte_suspend
,
327 .resume
= ptp_dte_resume
330 #define PTP_DTE_PM_OPS (&ptp_dte_pm_ops)
332 #define PTP_DTE_PM_OPS NULL
335 static const struct of_device_id ptp_dte_of_match
[] = {
336 { .compatible
= "brcm,ptp-dte", },
339 MODULE_DEVICE_TABLE(of
, ptp_dte_of_match
);
341 static struct platform_driver ptp_dte_driver
= {
344 .pm
= PTP_DTE_PM_OPS
,
345 .of_match_table
= ptp_dte_of_match
,
347 .probe
= ptp_dte_probe
,
348 .remove
= ptp_dte_remove
,
350 module_platform_driver(ptp_dte_driver
);
352 MODULE_AUTHOR("Broadcom");
353 MODULE_DESCRIPTION("Broadcom DTE PTP Clock driver");
354 MODULE_LICENSE("GPL v2");