xref: /OK3568_Linux_fs/kernel/drivers/net/phy/mii_timestamper.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Support for generic time stamping devices on MII buses.
4*4882a593Smuzhiyun // Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
5*4882a593Smuzhiyun //
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/mii_timestamper.h>
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun static LIST_HEAD(mii_timestamping_devices);
10*4882a593Smuzhiyun static DEFINE_MUTEX(tstamping_devices_lock);
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun struct mii_timestamping_desc {
13*4882a593Smuzhiyun 	struct list_head list;
14*4882a593Smuzhiyun 	struct mii_timestamping_ctrl *ctrl;
15*4882a593Smuzhiyun 	struct device *device;
16*4882a593Smuzhiyun };
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /**
19*4882a593Smuzhiyun  * register_mii_tstamp_controller() - registers an MII time stamping device.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * @device:	The device to be registered.
22*4882a593Smuzhiyun  * @ctrl:	Pointer to device's control interface.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Returns zero on success or non-zero on failure.
25*4882a593Smuzhiyun  */
register_mii_tstamp_controller(struct device * device,struct mii_timestamping_ctrl * ctrl)26*4882a593Smuzhiyun int register_mii_tstamp_controller(struct device *device,
27*4882a593Smuzhiyun 				   struct mii_timestamping_ctrl *ctrl)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	struct mii_timestamping_desc *desc;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
32*4882a593Smuzhiyun 	if (!desc)
33*4882a593Smuzhiyun 		return -ENOMEM;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	INIT_LIST_HEAD(&desc->list);
36*4882a593Smuzhiyun 	desc->ctrl = ctrl;
37*4882a593Smuzhiyun 	desc->device = device;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	mutex_lock(&tstamping_devices_lock);
40*4882a593Smuzhiyun 	list_add_tail(&mii_timestamping_devices, &desc->list);
41*4882a593Smuzhiyun 	mutex_unlock(&tstamping_devices_lock);
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun EXPORT_SYMBOL(register_mii_tstamp_controller);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun  * unregister_mii_tstamp_controller() - unregisters an MII time stamping device.
49*4882a593Smuzhiyun  *
50*4882a593Smuzhiyun  * @device:	A device previously passed to register_mii_tstamp_controller().
51*4882a593Smuzhiyun  */
unregister_mii_tstamp_controller(struct device * device)52*4882a593Smuzhiyun void unregister_mii_tstamp_controller(struct device *device)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	struct mii_timestamping_desc *desc;
55*4882a593Smuzhiyun 	struct list_head *this, *next;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	mutex_lock(&tstamping_devices_lock);
58*4882a593Smuzhiyun 	list_for_each_safe(this, next, &mii_timestamping_devices) {
59*4882a593Smuzhiyun 		desc = list_entry(this, struct mii_timestamping_desc, list);
60*4882a593Smuzhiyun 		if (desc->device == device) {
61*4882a593Smuzhiyun 			list_del_init(&desc->list);
62*4882a593Smuzhiyun 			kfree(desc);
63*4882a593Smuzhiyun 			break;
64*4882a593Smuzhiyun 		}
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 	mutex_unlock(&tstamping_devices_lock);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun EXPORT_SYMBOL(unregister_mii_tstamp_controller);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /**
71*4882a593Smuzhiyun  * register_mii_timestamper - Enables a given port of an MII time stamper.
72*4882a593Smuzhiyun  *
73*4882a593Smuzhiyun  * @node:	The device tree node of the MII time stamp controller.
74*4882a593Smuzhiyun  * @port:	The index of the port to be enabled.
75*4882a593Smuzhiyun  *
76*4882a593Smuzhiyun  * Returns a valid interface on success or ERR_PTR otherwise.
77*4882a593Smuzhiyun  */
register_mii_timestamper(struct device_node * node,unsigned int port)78*4882a593Smuzhiyun struct mii_timestamper *register_mii_timestamper(struct device_node *node,
79*4882a593Smuzhiyun 						 unsigned int port)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	struct mii_timestamper *mii_ts = NULL;
82*4882a593Smuzhiyun 	struct mii_timestamping_desc *desc;
83*4882a593Smuzhiyun 	struct list_head *this;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	mutex_lock(&tstamping_devices_lock);
86*4882a593Smuzhiyun 	list_for_each(this, &mii_timestamping_devices) {
87*4882a593Smuzhiyun 		desc = list_entry(this, struct mii_timestamping_desc, list);
88*4882a593Smuzhiyun 		if (desc->device->of_node == node) {
89*4882a593Smuzhiyun 			mii_ts = desc->ctrl->probe_channel(desc->device, port);
90*4882a593Smuzhiyun 			if (!IS_ERR(mii_ts)) {
91*4882a593Smuzhiyun 				mii_ts->device = desc->device;
92*4882a593Smuzhiyun 				get_device(desc->device);
93*4882a593Smuzhiyun 			}
94*4882a593Smuzhiyun 			break;
95*4882a593Smuzhiyun 		}
96*4882a593Smuzhiyun 	}
97*4882a593Smuzhiyun 	mutex_unlock(&tstamping_devices_lock);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	return mii_ts ? mii_ts : ERR_PTR(-EPROBE_DEFER);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun EXPORT_SYMBOL(register_mii_timestamper);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /**
104*4882a593Smuzhiyun  * unregister_mii_timestamper - Disables a given MII time stamper.
105*4882a593Smuzhiyun  *
106*4882a593Smuzhiyun  * @mii_ts:	An interface obtained via register_mii_timestamper().
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  */
unregister_mii_timestamper(struct mii_timestamper * mii_ts)109*4882a593Smuzhiyun void unregister_mii_timestamper(struct mii_timestamper *mii_ts)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct mii_timestamping_desc *desc;
112*4882a593Smuzhiyun 	struct list_head *this;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* mii_timestamper statically registered by the PHY driver won't use the
115*4882a593Smuzhiyun 	 * register_mii_timestamper() and thus don't have ->device set. Don't
116*4882a593Smuzhiyun 	 * try to unregister these.
117*4882a593Smuzhiyun 	 */
118*4882a593Smuzhiyun 	if (!mii_ts->device)
119*4882a593Smuzhiyun 		return;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	mutex_lock(&tstamping_devices_lock);
122*4882a593Smuzhiyun 	list_for_each(this, &mii_timestamping_devices) {
123*4882a593Smuzhiyun 		desc = list_entry(this, struct mii_timestamping_desc, list);
124*4882a593Smuzhiyun 		if (desc->device == mii_ts->device) {
125*4882a593Smuzhiyun 			desc->ctrl->release_channel(desc->device, mii_ts);
126*4882a593Smuzhiyun 			put_device(desc->device);
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun 		}
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 	mutex_unlock(&tstamping_devices_lock);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun EXPORT_SYMBOL(unregister_mii_timestamper);
133