1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PTP 1588 clock using the IXP46X
5 * Copyright (C) 2010 OMICRON electronics GmbH
7 #include <linux/device.h>
9 #include <linux/gpio.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
17 #include <linux/ptp_clock_kernel.h>
19 #include "ixp46x_ts.h"
21 #define DRIVER "ptp_ixp46x"
29 struct ixp46x_ts_regs
*regs
;
30 struct ptp_clock
*ptp_clock
;
31 struct ptp_clock_info caps
;
36 DEFINE_SPINLOCK(register_lock
);
39 * Register access functions
42 static u64
ixp_systime_read(struct ixp46x_ts_regs
*regs
)
47 lo
= __raw_readl(®s
->systime_lo
);
48 hi
= __raw_readl(®s
->systime_hi
);
50 ns
= ((u64
) hi
) << 32;
52 ns
<<= TICKS_NS_SHIFT
;
57 static void ixp_systime_write(struct ixp46x_ts_regs
*regs
, u64 ns
)
61 ns
>>= TICKS_NS_SHIFT
;
65 __raw_writel(lo
, ®s
->systime_lo
);
66 __raw_writel(hi
, ®s
->systime_hi
);
70 * Interrupt service routine
73 static irqreturn_t
isr(int irq
, void *priv
)
75 struct ixp_clock
*ixp_clock
= priv
;
76 struct ixp46x_ts_regs
*regs
= ixp_clock
->regs
;
77 struct ptp_clock_event event
;
78 u32 ack
= 0, lo
, hi
, val
;
80 val
= __raw_readl(®s
->event
);
84 if (ixp_clock
->exts0_enabled
) {
85 hi
= __raw_readl(®s
->asms_hi
);
86 lo
= __raw_readl(®s
->asms_lo
);
87 event
.type
= PTP_CLOCK_EXTTS
;
89 event
.timestamp
= ((u64
) hi
) << 32;
90 event
.timestamp
|= lo
;
91 event
.timestamp
<<= TICKS_NS_SHIFT
;
92 ptp_clock_event(ixp_clock
->ptp_clock
, &event
);
98 if (ixp_clock
->exts1_enabled
) {
99 hi
= __raw_readl(®s
->amms_hi
);
100 lo
= __raw_readl(®s
->amms_lo
);
101 event
.type
= PTP_CLOCK_EXTTS
;
103 event
.timestamp
= ((u64
) hi
) << 32;
104 event
.timestamp
|= lo
;
105 event
.timestamp
<<= TICKS_NS_SHIFT
;
106 ptp_clock_event(ixp_clock
->ptp_clock
, &event
);
111 ack
|= TTIPEND
; /* this bit seems to be always set */
114 __raw_writel(ack
, ®s
->event
);
121 * PTP clock operations
124 static int ptp_ixp_adjfreq(struct ptp_clock_info
*ptp
, s32 ppb
)
129 struct ixp_clock
*ixp_clock
= container_of(ptp
, struct ixp_clock
, caps
);
130 struct ixp46x_ts_regs
*regs
= ixp_clock
->regs
;
136 addend
= DEFAULT_ADDEND
;
139 diff
= div_u64(adj
, 1000000000ULL);
141 addend
= neg_adj
? addend
- diff
: addend
+ diff
;
143 __raw_writel(addend
, ®s
->addend
);
148 static int ptp_ixp_adjtime(struct ptp_clock_info
*ptp
, s64 delta
)
152 struct ixp_clock
*ixp_clock
= container_of(ptp
, struct ixp_clock
, caps
);
153 struct ixp46x_ts_regs
*regs
= ixp_clock
->regs
;
155 spin_lock_irqsave(®ister_lock
, flags
);
157 now
= ixp_systime_read(regs
);
159 ixp_systime_write(regs
, now
);
161 spin_unlock_irqrestore(®ister_lock
, flags
);
166 static int ptp_ixp_gettime(struct ptp_clock_info
*ptp
, struct timespec64
*ts
)
170 struct ixp_clock
*ixp_clock
= container_of(ptp
, struct ixp_clock
, caps
);
171 struct ixp46x_ts_regs
*regs
= ixp_clock
->regs
;
173 spin_lock_irqsave(®ister_lock
, flags
);
175 ns
= ixp_systime_read(regs
);
177 spin_unlock_irqrestore(®ister_lock
, flags
);
179 *ts
= ns_to_timespec64(ns
);
183 static int ptp_ixp_settime(struct ptp_clock_info
*ptp
,
184 const struct timespec64
*ts
)
188 struct ixp_clock
*ixp_clock
= container_of(ptp
, struct ixp_clock
, caps
);
189 struct ixp46x_ts_regs
*regs
= ixp_clock
->regs
;
191 ns
= timespec64_to_ns(ts
);
193 spin_lock_irqsave(®ister_lock
, flags
);
195 ixp_systime_write(regs
, ns
);
197 spin_unlock_irqrestore(®ister_lock
, flags
);
202 static int ptp_ixp_enable(struct ptp_clock_info
*ptp
,
203 struct ptp_clock_request
*rq
, int on
)
205 struct ixp_clock
*ixp_clock
= container_of(ptp
, struct ixp_clock
, caps
);
208 case PTP_CLK_REQ_EXTTS
:
209 switch (rq
->extts
.index
) {
211 ixp_clock
->exts0_enabled
= on
? 1 : 0;
214 ixp_clock
->exts1_enabled
= on
? 1 : 0;
227 static const struct ptp_clock_info ptp_ixp_caps
= {
228 .owner
= THIS_MODULE
,
229 .name
= "IXP46X timer",
231 .n_ext_ts
= N_EXT_TS
,
234 .adjfreq
= ptp_ixp_adjfreq
,
235 .adjtime
= ptp_ixp_adjtime
,
236 .gettime64
= ptp_ixp_gettime
,
237 .settime64
= ptp_ixp_settime
,
238 .enable
= ptp_ixp_enable
,
241 /* module operations */
243 static struct ixp_clock ixp_clock
;
245 static int setup_interrupt(int gpio
)
250 err
= gpio_request(gpio
, "ixp4-ptp");
254 err
= gpio_direction_input(gpio
);
258 irq
= gpio_to_irq(gpio
);
262 err
= irq_set_irq_type(irq
, IRQF_TRIGGER_FALLING
);
264 pr_err("cannot set trigger type for irq %d\n", irq
);
268 err
= request_irq(irq
, isr
, 0, DRIVER
, &ixp_clock
);
270 pr_err("request_irq failed for irq %d\n", irq
);
277 static void __exit
ptp_ixp_exit(void)
279 free_irq(MASTER_IRQ
, &ixp_clock
);
280 free_irq(SLAVE_IRQ
, &ixp_clock
);
281 ixp46x_phc_index
= -1;
282 ptp_clock_unregister(ixp_clock
.ptp_clock
);
285 static int __init
ptp_ixp_init(void)
287 if (!cpu_is_ixp46x())
291 (struct ixp46x_ts_regs __iomem
*) IXP4XX_TIMESYNC_BASE_VIRT
;
293 ixp_clock
.caps
= ptp_ixp_caps
;
295 ixp_clock
.ptp_clock
= ptp_clock_register(&ixp_clock
.caps
, NULL
);
297 if (IS_ERR(ixp_clock
.ptp_clock
))
298 return PTR_ERR(ixp_clock
.ptp_clock
);
300 ixp46x_phc_index
= ptp_clock_index(ixp_clock
.ptp_clock
);
302 __raw_writel(DEFAULT_ADDEND
, &ixp_clock
.regs
->addend
);
303 __raw_writel(1, &ixp_clock
.regs
->trgt_lo
);
304 __raw_writel(0, &ixp_clock
.regs
->trgt_hi
);
305 __raw_writel(TTIPEND
, &ixp_clock
.regs
->event
);
307 if (MASTER_IRQ
!= setup_interrupt(MASTER_GPIO
)) {
308 pr_err("failed to setup gpio %d as irq\n", MASTER_GPIO
);
311 if (SLAVE_IRQ
!= setup_interrupt(SLAVE_GPIO
)) {
312 pr_err("failed to setup gpio %d as irq\n", SLAVE_GPIO
);
318 free_irq(MASTER_IRQ
, &ixp_clock
);
320 ptp_clock_unregister(ixp_clock
.ptp_clock
);
324 module_init(ptp_ixp_init
);
325 module_exit(ptp_ixp_exit
);
327 MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
328 MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
329 MODULE_LICENSE("GPL");