1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (C) 2018 MOSER-BAER AG
6 #define pr_fmt(fmt) "InES_PTP: " fmt
8 #include <linux/ethtool.h>
9 #include <linux/export.h>
10 #include <linux/if_vlan.h>
11 #include <linux/mii_timestamper.h>
12 #include <linux/module.h>
13 #include <linux/net_tstamp.h>
15 #include <linux/of_address.h>
16 #include <linux/of_irq.h>
17 #include <linux/phy.h>
18 #include <linux/platform_device.h>
19 #include <linux/ptp_classify.h>
20 #include <linux/ptp_clock_kernel.h>
21 #include <linux/stddef.h>
23 MODULE_DESCRIPTION("Driver for the ZHAW InES PTP time stamping IP core");
24 MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
25 MODULE_VERSION("1.0");
26 MODULE_LICENSE("GPL");
29 #define MCAST_MAC_SELECT_SHIFT 2
30 #define MCAST_MAC_SELECT_MASK 0x3
31 #define IO_RESET BIT(1)
32 #define PTP_RESET BIT(0)
34 /* VERSION register */
35 #define IF_MAJOR_VER_SHIFT 12
36 #define IF_MAJOR_VER_MASK 0xf
37 #define IF_MINOR_VER_SHIFT 8
38 #define IF_MINOR_VER_MASK 0xf
39 #define FPGA_MAJOR_VER_SHIFT 4
40 #define FPGA_MAJOR_VER_MASK 0xf
41 #define FPGA_MINOR_VER_SHIFT 0
42 #define FPGA_MINOR_VER_MASK 0xf
44 /* INT_STAT register */
45 #define RX_INTR_STATUS_3 BIT(5)
46 #define RX_INTR_STATUS_2 BIT(4)
47 #define RX_INTR_STATUS_1 BIT(3)
48 #define TX_INTR_STATUS_3 BIT(2)
49 #define TX_INTR_STATUS_2 BIT(1)
50 #define TX_INTR_STATUS_1 BIT(0)
52 /* INT_MSK register */
53 #define RX_INTR_MASK_3 BIT(5)
54 #define RX_INTR_MASK_2 BIT(4)
55 #define RX_INTR_MASK_1 BIT(3)
56 #define TX_INTR_MASK_3 BIT(2)
57 #define TX_INTR_MASK_2 BIT(1)
58 #define TX_INTR_MASK_1 BIT(0)
60 /* BUF_STAT register */
61 #define RX_FIFO_NE_3 BIT(5)
62 #define RX_FIFO_NE_2 BIT(4)
63 #define RX_FIFO_NE_1 BIT(3)
64 #define TX_FIFO_NE_3 BIT(2)
65 #define TX_FIFO_NE_2 BIT(1)
66 #define TX_FIFO_NE_1 BIT(0)
68 /* PORT_CONF register */
69 #define CM_ONE_STEP BIT(6)
70 #define PHY_SPEED_SHIFT 4
71 #define PHY_SPEED_MASK 0x3
72 #define P2P_DELAY_WR_POS_SHIFT 2
73 #define P2P_DELAY_WR_POS_MASK 0x3
74 #define PTP_MODE_SHIFT 0
75 #define PTP_MODE_MASK 0x3
77 /* TS_STAT_TX register */
78 #define TS_ENABLE BIT(15)
79 #define DATA_READ_POS_SHIFT 8
80 #define DATA_READ_POS_MASK 0x1f
81 #define DISCARDED_EVENTS_SHIFT 4
82 #define DISCARDED_EVENTS_MASK 0xf
84 #define INES_N_PORTS 3
85 #define INES_REGISTER_SIZE 0x80
86 #define INES_PORT_OFFSET 0x20
87 #define INES_PORT_SIZE 0x20
88 #define INES_FIFO_DEPTH 90
89 #define INES_MAX_EVENTS 100
93 #define TC_E2E_PTP_V2 2
94 #define TC_P2P_PTP_V2 3
96 #define OFF_PTP_CLOCK_ID 20
97 #define OFF_PTP_PORT_NUM 28
99 #define PHY_SPEED_10 0
100 #define PHY_SPEED_100 1
101 #define PHY_SPEED_1000 2
104 ((PHY_SPEED_1000 << PHY_SPEED_SHIFT) | (BC_PTP_V2 << PTP_MODE_SHIFT))
106 #define ines_read32(s, r) __raw_readl((void __iomem *)&s->regs->r)
107 #define ines_write32(s, v, r) __raw_writel(v, (void __iomem *)&s->regs->r)
109 #define MESSAGE_TYPE_SYNC 1
110 #define MESSAGE_TYPE_P_DELAY_REQ 2
111 #define MESSAGE_TYPE_P_DELAY_RESP 3
112 #define MESSAGE_TYPE_DELAY_REQ 4
115 #define DELAY_REQ 0x1
116 #define PDELAY_REQ 0x2
117 #define PDELAY_RESP 0x3
119 static LIST_HEAD(ines_clocks
);
120 static DEFINE_MUTEX(ines_clocks_lock
);
122 struct ines_global_regs
{
133 struct ines_port_registers
{
142 struct ines_timestamp
{
143 struct list_head list
;
154 struct ines_port_registers
*regs
;
155 struct mii_timestamper mii_ts
;
156 struct ines_clock
*clock
;
160 struct delayed_work ts_work
;
161 /* lock protects event list and tx_skb */
163 struct sk_buff
*tx_skb
;
164 struct list_head events
;
165 struct list_head pool
;
166 struct ines_timestamp pool_data
[INES_MAX_EVENTS
];
170 struct ines_port port
[INES_N_PORTS
];
171 struct ines_global_regs __iomem
*regs
;
173 struct device_node
*node
;
175 struct list_head list
;
178 static bool ines_match(struct sk_buff
*skb
, unsigned int ptp_class
,
179 struct ines_timestamp
*ts
, struct device
*dev
);
180 static int ines_rxfifo_read(struct ines_port
*port
);
181 static u64
ines_rxts64(struct ines_port
*port
, unsigned int words
);
182 static bool ines_timestamp_expired(struct ines_timestamp
*ts
);
183 static u64
ines_txts64(struct ines_port
*port
, unsigned int words
);
184 static void ines_txtstamp_work(struct work_struct
*work
);
185 static bool is_sync_pdelay_resp(struct sk_buff
*skb
, int type
);
186 static u8
tag_to_msgtype(u8 tag
);
188 static void ines_clock_cleanup(struct ines_clock
*clock
)
190 struct ines_port
*port
;
193 for (i
= 0; i
< INES_N_PORTS
; i
++) {
194 port
= &clock
->port
[i
];
195 cancel_delayed_work_sync(&port
->ts_work
);
199 static int ines_clock_init(struct ines_clock
*clock
, struct device
*device
,
202 struct device_node
*node
= device
->of_node
;
203 unsigned long port_addr
;
204 struct ines_port
*port
;
207 INIT_LIST_HEAD(&clock
->list
);
211 clock
->regs
= clock
->base
;
213 for (i
= 0; i
< INES_N_PORTS
; i
++) {
214 port
= &clock
->port
[i
];
215 port_addr
= (unsigned long) clock
->base
+
216 INES_PORT_OFFSET
+ i
* INES_PORT_SIZE
;
217 port
->regs
= (struct ines_port_registers
*) port_addr
;
220 INIT_DELAYED_WORK(&port
->ts_work
, ines_txtstamp_work
);
221 spin_lock_init(&port
->lock
);
222 INIT_LIST_HEAD(&port
->events
);
223 INIT_LIST_HEAD(&port
->pool
);
224 for (j
= 0; j
< INES_MAX_EVENTS
; j
++)
225 list_add(&port
->pool_data
[j
].list
, &port
->pool
);
228 ines_write32(clock
, 0xBEEF, test
);
229 ines_write32(clock
, 0xBEEF, test2
);
231 dev_dbg(device
, "ID 0x%x\n", ines_read32(clock
, id
));
232 dev_dbg(device
, "TEST 0x%x\n", ines_read32(clock
, test
));
233 dev_dbg(device
, "VERSION 0x%x\n", ines_read32(clock
, version
));
234 dev_dbg(device
, "TEST2 0x%x\n", ines_read32(clock
, test2
));
236 for (i
= 0; i
< INES_N_PORTS
; i
++) {
237 port
= &clock
->port
[i
];
238 ines_write32(port
, PORT_CONF
, port_conf
);
244 static struct ines_port
*ines_find_port(struct device_node
*node
, u32 index
)
246 struct ines_port
*port
= NULL
;
247 struct ines_clock
*clock
;
248 struct list_head
*this;
250 mutex_lock(&ines_clocks_lock
);
251 list_for_each(this, &ines_clocks
) {
252 clock
= list_entry(this, struct ines_clock
, list
);
253 if (clock
->node
== node
) {
254 port
= &clock
->port
[index
];
258 mutex_unlock(&ines_clocks_lock
);
262 static u64
ines_find_rxts(struct ines_port
*port
, struct sk_buff
*skb
, int type
)
264 struct list_head
*this, *next
;
265 struct ines_timestamp
*ts
;
269 if (type
== PTP_CLASS_NONE
)
272 spin_lock_irqsave(&port
->lock
, flags
);
273 ines_rxfifo_read(port
);
274 list_for_each_safe(this, next
, &port
->events
) {
275 ts
= list_entry(this, struct ines_timestamp
, list
);
276 if (ines_timestamp_expired(ts
)) {
277 list_del_init(&ts
->list
);
278 list_add(&ts
->list
, &port
->pool
);
281 if (ines_match(skb
, type
, ts
, port
->clock
->dev
)) {
282 ns
= ts
->sec
* 1000000000ULL + ts
->nsec
;
283 list_del_init(&ts
->list
);
284 list_add(&ts
->list
, &port
->pool
);
288 spin_unlock_irqrestore(&port
->lock
, flags
);
293 static u64
ines_find_txts(struct ines_port
*port
, struct sk_buff
*skb
)
295 unsigned int class = ptp_classify_raw(skb
), i
;
296 u32 data_rd_pos
, buf_stat
, mask
, ts_stat_tx
;
297 struct ines_timestamp ts
;
301 mask
= TX_FIFO_NE_1
<< port
->index
;
303 spin_lock_irqsave(&port
->lock
, flags
);
305 for (i
= 0; i
< INES_FIFO_DEPTH
; i
++) {
307 buf_stat
= ines_read32(port
->clock
, buf_stat
);
308 if (!(buf_stat
& mask
)) {
309 dev_dbg(port
->clock
->dev
,
310 "Tx timestamp FIFO unexpectedly empty\n");
313 ts_stat_tx
= ines_read32(port
, ts_stat_tx
);
314 data_rd_pos
= (ts_stat_tx
>> DATA_READ_POS_SHIFT
) &
317 dev_err(port
->clock
->dev
,
318 "unexpected Tx read pos %u\n", data_rd_pos
);
322 ts
.tag
= ines_read32(port
, ts_tx
);
323 ts
.sec
= ines_txts64(port
, 3);
324 ts
.nsec
= ines_txts64(port
, 2);
325 ts
.clkid
= ines_txts64(port
, 4);
326 ts
.portnum
= ines_read32(port
, ts_tx
);
327 ts
.seqid
= ines_read32(port
, ts_tx
);
329 if (ines_match(skb
, class, &ts
, port
->clock
->dev
)) {
330 ns
= ts
.sec
* 1000000000ULL + ts
.nsec
;
335 spin_unlock_irqrestore(&port
->lock
, flags
);
339 static int ines_hwtstamp(struct mii_timestamper
*mii_ts
, struct ifreq
*ifr
)
341 struct ines_port
*port
= container_of(mii_ts
, struct ines_port
, mii_ts
);
342 u32 cm_one_step
= 0, port_conf
, ts_stat_rx
, ts_stat_tx
;
343 struct hwtstamp_config cfg
;
346 if (copy_from_user(&cfg
, ifr
->ifr_data
, sizeof(cfg
)))
349 /* reserved for future extensions */
353 switch (cfg
.tx_type
) {
354 case HWTSTAMP_TX_OFF
:
358 ts_stat_tx
= TS_ENABLE
;
360 case HWTSTAMP_TX_ONESTEP_P2P
:
361 ts_stat_tx
= TS_ENABLE
;
362 cm_one_step
= CM_ONE_STEP
;
368 switch (cfg
.rx_filter
) {
369 case HWTSTAMP_FILTER_NONE
:
372 case HWTSTAMP_FILTER_ALL
:
373 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT
:
374 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC
:
375 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ
:
377 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT
:
378 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC
:
379 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ
:
380 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT
:
381 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC
:
382 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ
:
383 case HWTSTAMP_FILTER_PTP_V2_EVENT
:
384 case HWTSTAMP_FILTER_PTP_V2_SYNC
:
385 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ
:
386 ts_stat_rx
= TS_ENABLE
;
387 cfg
.rx_filter
= HWTSTAMP_FILTER_PTP_V2_EVENT
;
393 spin_lock_irqsave(&port
->lock
, flags
);
395 port_conf
= ines_read32(port
, port_conf
);
396 port_conf
&= ~CM_ONE_STEP
;
397 port_conf
|= cm_one_step
;
399 ines_write32(port
, port_conf
, port_conf
);
400 ines_write32(port
, ts_stat_rx
, ts_stat_rx
);
401 ines_write32(port
, ts_stat_tx
, ts_stat_tx
);
403 port
->rxts_enabled
= ts_stat_rx
== TS_ENABLE
? true : false;
404 port
->txts_enabled
= ts_stat_tx
== TS_ENABLE
? true : false;
406 spin_unlock_irqrestore(&port
->lock
, flags
);
408 return copy_to_user(ifr
->ifr_data
, &cfg
, sizeof(cfg
)) ? -EFAULT
: 0;
411 static void ines_link_state(struct mii_timestamper
*mii_ts
,
412 struct phy_device
*phydev
)
414 struct ines_port
*port
= container_of(mii_ts
, struct ines_port
, mii_ts
);
415 u32 port_conf
, speed_conf
;
418 switch (phydev
->speed
) {
420 speed_conf
= PHY_SPEED_10
<< PHY_SPEED_SHIFT
;
423 speed_conf
= PHY_SPEED_100
<< PHY_SPEED_SHIFT
;
426 speed_conf
= PHY_SPEED_1000
<< PHY_SPEED_SHIFT
;
429 dev_err(port
->clock
->dev
, "bad speed: %d\n", phydev
->speed
);
432 spin_lock_irqsave(&port
->lock
, flags
);
434 port_conf
= ines_read32(port
, port_conf
);
435 port_conf
&= ~(0x3 << PHY_SPEED_SHIFT
);
436 port_conf
|= speed_conf
;
438 ines_write32(port
, port_conf
, port_conf
);
440 spin_unlock_irqrestore(&port
->lock
, flags
);
443 static bool ines_match(struct sk_buff
*skb
, unsigned int ptp_class
,
444 struct ines_timestamp
*ts
, struct device
*dev
)
446 u8
*msgtype
, *data
= skb_mac_header(skb
);
447 unsigned int offset
= 0;
448 __be16
*portn
, *seqid
;
451 if (unlikely(ptp_class
& PTP_CLASS_V1
))
454 if (ptp_class
& PTP_CLASS_VLAN
)
457 switch (ptp_class
& PTP_CLASS_PMASK
) {
459 offset
+= ETH_HLEN
+ IPV4_HLEN(data
+ offset
) + UDP_HLEN
;
462 offset
+= ETH_HLEN
+ IP6_HLEN
+ UDP_HLEN
;
471 if (skb
->len
+ ETH_HLEN
< offset
+ OFF_PTP_SEQUENCE_ID
+ sizeof(*seqid
))
474 msgtype
= data
+ offset
;
475 clkid
= (__be64
*)(data
+ offset
+ OFF_PTP_CLOCK_ID
);
476 portn
= (__be16
*)(data
+ offset
+ OFF_PTP_PORT_NUM
);
477 seqid
= (__be16
*)(data
+ offset
+ OFF_PTP_SEQUENCE_ID
);
479 if (tag_to_msgtype(ts
->tag
& 0x7) != (*msgtype
& 0xf)) {
480 dev_dbg(dev
, "msgtype mismatch ts %hhu != skb %hhu\n",
481 tag_to_msgtype(ts
->tag
& 0x7), *msgtype
& 0xf);
484 if (cpu_to_be64(ts
->clkid
) != *clkid
) {
485 dev_dbg(dev
, "clkid mismatch ts %llx != skb %llx\n",
486 cpu_to_be64(ts
->clkid
), *clkid
);
489 if (ts
->portnum
!= ntohs(*portn
)) {
490 dev_dbg(dev
, "portn mismatch ts %hu != skb %hu\n",
491 ts
->portnum
, ntohs(*portn
));
494 if (ts
->seqid
!= ntohs(*seqid
)) {
495 dev_dbg(dev
, "seqid mismatch ts %hu != skb %hu\n",
496 ts
->seqid
, ntohs(*seqid
));
503 static bool ines_rxtstamp(struct mii_timestamper
*mii_ts
,
504 struct sk_buff
*skb
, int type
)
506 struct ines_port
*port
= container_of(mii_ts
, struct ines_port
, mii_ts
);
507 struct skb_shared_hwtstamps
*ssh
;
510 if (!port
->rxts_enabled
)
513 ns
= ines_find_rxts(port
, skb
, type
);
517 ssh
= skb_hwtstamps(skb
);
518 ssh
->hwtstamp
= ns_to_ktime(ns
);
524 static int ines_rxfifo_read(struct ines_port
*port
)
526 u32 data_rd_pos
, buf_stat
, mask
, ts_stat_rx
;
527 struct ines_timestamp
*ts
;
530 mask
= RX_FIFO_NE_1
<< port
->index
;
532 for (i
= 0; i
< INES_FIFO_DEPTH
; i
++) {
533 if (list_empty(&port
->pool
)) {
534 dev_err(port
->clock
->dev
, "event pool is empty\n");
537 buf_stat
= ines_read32(port
->clock
, buf_stat
);
538 if (!(buf_stat
& mask
))
541 ts_stat_rx
= ines_read32(port
, ts_stat_rx
);
542 data_rd_pos
= (ts_stat_rx
>> DATA_READ_POS_SHIFT
) &
545 dev_err(port
->clock
->dev
, "unexpected Rx read pos %u\n",
550 ts
= list_first_entry(&port
->pool
, struct ines_timestamp
, list
);
551 ts
->tmo
= jiffies
+ HZ
;
552 ts
->tag
= ines_read32(port
, ts_rx
);
553 ts
->sec
= ines_rxts64(port
, 3);
554 ts
->nsec
= ines_rxts64(port
, 2);
555 ts
->clkid
= ines_rxts64(port
, 4);
556 ts
->portnum
= ines_read32(port
, ts_rx
);
557 ts
->seqid
= ines_read32(port
, ts_rx
);
559 list_del_init(&ts
->list
);
560 list_add_tail(&ts
->list
, &port
->events
);
566 static u64
ines_rxts64(struct ines_port
*port
, unsigned int words
)
572 word
= ines_read32(port
, ts_rx
);
575 for (i
= 0; i
< words
; i
++) {
576 word
= ines_read32(port
, ts_rx
);
583 static bool ines_timestamp_expired(struct ines_timestamp
*ts
)
585 return time_after(jiffies
, ts
->tmo
);
588 static int ines_ts_info(struct mii_timestamper
*mii_ts
,
589 struct ethtool_ts_info
*info
)
591 info
->so_timestamping
=
592 SOF_TIMESTAMPING_TX_HARDWARE
|
593 SOF_TIMESTAMPING_TX_SOFTWARE
|
594 SOF_TIMESTAMPING_RX_HARDWARE
|
595 SOF_TIMESTAMPING_RX_SOFTWARE
|
596 SOF_TIMESTAMPING_SOFTWARE
|
597 SOF_TIMESTAMPING_RAW_HARDWARE
;
599 info
->phc_index
= -1;
602 (1 << HWTSTAMP_TX_OFF
) |
603 (1 << HWTSTAMP_TX_ON
) |
604 (1 << HWTSTAMP_TX_ONESTEP_P2P
);
607 (1 << HWTSTAMP_FILTER_NONE
) |
608 (1 << HWTSTAMP_FILTER_PTP_V2_EVENT
);
613 static u64
ines_txts64(struct ines_port
*port
, unsigned int words
)
619 word
= ines_read32(port
, ts_tx
);
622 for (i
= 0; i
< words
; i
++) {
623 word
= ines_read32(port
, ts_tx
);
630 static bool ines_txts_onestep(struct ines_port
*port
, struct sk_buff
*skb
, int type
)
635 spin_lock_irqsave(&port
->lock
, flags
);
636 port_conf
= ines_read32(port
, port_conf
);
637 spin_unlock_irqrestore(&port
->lock
, flags
);
639 if (port_conf
& CM_ONE_STEP
)
640 return is_sync_pdelay_resp(skb
, type
);
645 static void ines_txtstamp(struct mii_timestamper
*mii_ts
,
646 struct sk_buff
*skb
, int type
)
648 struct ines_port
*port
= container_of(mii_ts
, struct ines_port
, mii_ts
);
649 struct sk_buff
*old_skb
= NULL
;
652 if (!port
->txts_enabled
|| ines_txts_onestep(port
, skb
, type
)) {
657 spin_lock_irqsave(&port
->lock
, flags
);
660 old_skb
= port
->tx_skb
;
664 spin_unlock_irqrestore(&port
->lock
, flags
);
669 schedule_delayed_work(&port
->ts_work
, 1);
672 static void ines_txtstamp_work(struct work_struct
*work
)
674 struct ines_port
*port
=
675 container_of(work
, struct ines_port
, ts_work
.work
);
676 struct skb_shared_hwtstamps ssh
;
681 spin_lock_irqsave(&port
->lock
, flags
);
684 spin_unlock_irqrestore(&port
->lock
, flags
);
686 ns
= ines_find_txts(port
, skb
);
691 ssh
.hwtstamp
= ns_to_ktime(ns
);
692 skb_complete_tx_timestamp(skb
, &ssh
);
695 static bool is_sync_pdelay_resp(struct sk_buff
*skb
, int type
)
697 u8
*data
= skb
->data
, *msgtype
;
698 unsigned int offset
= 0;
700 if (type
& PTP_CLASS_VLAN
)
703 switch (type
& PTP_CLASS_PMASK
) {
705 offset
+= ETH_HLEN
+ IPV4_HLEN(data
+ offset
) + UDP_HLEN
;
708 offset
+= ETH_HLEN
+ IP6_HLEN
+ UDP_HLEN
;
717 if (type
& PTP_CLASS_V1
)
718 offset
+= OFF_PTP_CONTROL
;
720 if (skb
->len
< offset
+ 1)
723 msgtype
= data
+ offset
;
725 switch ((*msgtype
& 0xf)) {
734 static u8
tag_to_msgtype(u8 tag
)
737 case MESSAGE_TYPE_SYNC
:
739 case MESSAGE_TYPE_P_DELAY_REQ
:
741 case MESSAGE_TYPE_P_DELAY_RESP
:
743 case MESSAGE_TYPE_DELAY_REQ
:
749 static struct mii_timestamper
*ines_ptp_probe_channel(struct device
*device
,
752 struct device_node
*node
= device
->of_node
;
753 struct ines_port
*port
;
755 if (index
> INES_N_PORTS
- 1) {
756 dev_err(device
, "bad port index %u\n", index
);
757 return ERR_PTR(-EINVAL
);
759 port
= ines_find_port(node
, index
);
761 dev_err(device
, "missing port index %u\n", index
);
762 return ERR_PTR(-ENODEV
);
764 port
->mii_ts
.rxtstamp
= ines_rxtstamp
;
765 port
->mii_ts
.txtstamp
= ines_txtstamp
;
766 port
->mii_ts
.hwtstamp
= ines_hwtstamp
;
767 port
->mii_ts
.link_state
= ines_link_state
;
768 port
->mii_ts
.ts_info
= ines_ts_info
;
770 return &port
->mii_ts
;
773 static void ines_ptp_release_channel(struct device
*device
,
774 struct mii_timestamper
*mii_ts
)
778 static struct mii_timestamping_ctrl ines_ctrl
= {
779 .probe_channel
= ines_ptp_probe_channel
,
780 .release_channel
= ines_ptp_release_channel
,
783 static int ines_ptp_ctrl_probe(struct platform_device
*pld
)
785 struct ines_clock
*clock
;
786 struct resource
*res
;
790 res
= platform_get_resource(pld
, IORESOURCE_MEM
, 0);
792 dev_err(&pld
->dev
, "missing memory resource\n");
795 addr
= devm_ioremap_resource(&pld
->dev
, res
);
800 clock
= kzalloc(sizeof(*clock
), GFP_KERNEL
);
805 if (ines_clock_init(clock
, &pld
->dev
, addr
)) {
810 err
= register_mii_tstamp_controller(&pld
->dev
, &ines_ctrl
);
815 mutex_lock(&ines_clocks_lock
);
816 list_add_tail(&ines_clocks
, &clock
->list
);
817 mutex_unlock(&ines_clocks_lock
);
819 dev_set_drvdata(&pld
->dev
, clock
);
824 static int ines_ptp_ctrl_remove(struct platform_device
*pld
)
826 struct ines_clock
*clock
= dev_get_drvdata(&pld
->dev
);
828 unregister_mii_tstamp_controller(&pld
->dev
);
829 mutex_lock(&ines_clocks_lock
);
830 list_del(&clock
->list
);
831 mutex_unlock(&ines_clocks_lock
);
832 ines_clock_cleanup(clock
);
837 static const struct of_device_id ines_ptp_ctrl_of_match
[] = {
838 { .compatible
= "ines,ptp-ctrl" },
842 MODULE_DEVICE_TABLE(of
, ines_ptp_ctrl_of_match
);
844 static struct platform_driver ines_ptp_ctrl_driver
= {
845 .probe
= ines_ptp_ctrl_probe
,
846 .remove
= ines_ptp_ctrl_remove
,
848 .name
= "ines_ptp_ctrl",
849 .of_match_table
= of_match_ptr(ines_ptp_ctrl_of_match
),
852 module_platform_driver(ines_ptp_ctrl_driver
);