1 // SPDX-License-Identifier: GPL-2.0
3 // Support for generic time stamping devices on MII buses.
4 // Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
7 #include <linux/mii_timestamper.h>
9 static LIST_HEAD(mii_timestamping_devices
);
10 static DEFINE_MUTEX(tstamping_devices_lock
);
12 struct mii_timestamping_desc
{
13 struct list_head list
;
14 struct mii_timestamping_ctrl
*ctrl
;
15 struct device
*device
;
19 * register_mii_tstamp_controller() - registers an MII time stamping device.
21 * @device: The device to be registered.
22 * @ctrl: Pointer to device's control interface.
24 * Returns zero on success or non-zero on failure.
26 int register_mii_tstamp_controller(struct device
*device
,
27 struct mii_timestamping_ctrl
*ctrl
)
29 struct mii_timestamping_desc
*desc
;
31 desc
= kzalloc(sizeof(*desc
), GFP_KERNEL
);
35 INIT_LIST_HEAD(&desc
->list
);
37 desc
->device
= device
;
39 mutex_lock(&tstamping_devices_lock
);
40 list_add_tail(&mii_timestamping_devices
, &desc
->list
);
41 mutex_unlock(&tstamping_devices_lock
);
45 EXPORT_SYMBOL(register_mii_tstamp_controller
);
48 * unregister_mii_tstamp_controller() - unregisters an MII time stamping device.
50 * @device: A device previously passed to register_mii_tstamp_controller().
52 void unregister_mii_tstamp_controller(struct device
*device
)
54 struct mii_timestamping_desc
*desc
;
55 struct list_head
*this, *next
;
57 mutex_lock(&tstamping_devices_lock
);
58 list_for_each_safe(this, next
, &mii_timestamping_devices
) {
59 desc
= list_entry(this, struct mii_timestamping_desc
, list
);
60 if (desc
->device
== device
) {
61 list_del_init(&desc
->list
);
66 mutex_unlock(&tstamping_devices_lock
);
68 EXPORT_SYMBOL(unregister_mii_tstamp_controller
);
71 * register_mii_timestamper - Enables a given port of an MII time stamper.
73 * @node: The device tree node of the MII time stamp controller.
74 * @port: The index of the port to be enabled.
76 * Returns a valid interface on success or ERR_PTR otherwise.
78 struct mii_timestamper
*register_mii_timestamper(struct device_node
*node
,
81 struct mii_timestamper
*mii_ts
= NULL
;
82 struct mii_timestamping_desc
*desc
;
83 struct list_head
*this;
85 mutex_lock(&tstamping_devices_lock
);
86 list_for_each(this, &mii_timestamping_devices
) {
87 desc
= list_entry(this, struct mii_timestamping_desc
, list
);
88 if (desc
->device
->of_node
== node
) {
89 mii_ts
= desc
->ctrl
->probe_channel(desc
->device
, port
);
90 if (!IS_ERR(mii_ts
)) {
91 mii_ts
->device
= desc
->device
;
92 get_device(desc
->device
);
97 mutex_unlock(&tstamping_devices_lock
);
99 return mii_ts
? mii_ts
: ERR_PTR(-EPROBE_DEFER
);
101 EXPORT_SYMBOL(register_mii_timestamper
);
104 * unregister_mii_timestamper - Disables a given MII time stamper.
106 * @mii_ts: An interface obtained via register_mii_timestamper().
109 void unregister_mii_timestamper(struct mii_timestamper
*mii_ts
)
111 struct mii_timestamping_desc
*desc
;
112 struct list_head
*this;
114 /* mii_timestamper statically registered by the PHY driver won't use the
115 * register_mii_timestamper() and thus don't have ->device set. Don't
116 * try to unregister these.
121 mutex_lock(&tstamping_devices_lock
);
122 list_for_each(this, &mii_timestamping_devices
) {
123 desc
= list_entry(this, struct mii_timestamping_desc
, list
);
124 if (desc
->device
== mii_ts
->device
) {
125 desc
->ctrl
->release_channel(desc
->device
, mii_ts
);
126 put_device(desc
->device
);
130 mutex_unlock(&tstamping_devices_lock
);
132 EXPORT_SYMBOL(unregister_mii_timestamper
);