1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun #include <linux/device.h>
4*4882a593Smuzhiyun #include <linux/of_mdio.h>
5*4882a593Smuzhiyun #include <linux/phy.h>
6*4882a593Smuzhiyun #include <linux/stddef.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun struct mdiobus_devres {
9*4882a593Smuzhiyun struct mii_bus *mii;
10*4882a593Smuzhiyun };
11*4882a593Smuzhiyun
devm_mdiobus_free(struct device * dev,void * this)12*4882a593Smuzhiyun static void devm_mdiobus_free(struct device *dev, void *this)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun struct mdiobus_devres *dr = this;
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun mdiobus_free(dr->mii);
17*4882a593Smuzhiyun }
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /**
20*4882a593Smuzhiyun * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size()
21*4882a593Smuzhiyun * @dev: Device to allocate mii_bus for
22*4882a593Smuzhiyun * @sizeof_priv: Space to allocate for private structure
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Managed mdiobus_alloc_size. mii_bus allocated with this function is
25*4882a593Smuzhiyun * automatically freed on driver detach.
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * RETURNS:
28*4882a593Smuzhiyun * Pointer to allocated mii_bus on success, NULL on out-of-memory error.
29*4882a593Smuzhiyun */
devm_mdiobus_alloc_size(struct device * dev,int sizeof_priv)30*4882a593Smuzhiyun struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun struct mdiobus_devres *dr;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun dr = devres_alloc(devm_mdiobus_free, sizeof(*dr), GFP_KERNEL);
35*4882a593Smuzhiyun if (!dr)
36*4882a593Smuzhiyun return NULL;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun dr->mii = mdiobus_alloc_size(sizeof_priv);
39*4882a593Smuzhiyun if (!dr->mii) {
40*4882a593Smuzhiyun devres_free(dr);
41*4882a593Smuzhiyun return NULL;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun devres_add(dev, dr);
45*4882a593Smuzhiyun return dr->mii;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun EXPORT_SYMBOL(devm_mdiobus_alloc_size);
48*4882a593Smuzhiyun
devm_mdiobus_unregister(struct device * dev,void * this)49*4882a593Smuzhiyun static void devm_mdiobus_unregister(struct device *dev, void *this)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun struct mdiobus_devres *dr = this;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun mdiobus_unregister(dr->mii);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
mdiobus_devres_match(struct device * dev,void * this,void * match_data)56*4882a593Smuzhiyun static int mdiobus_devres_match(struct device *dev,
57*4882a593Smuzhiyun void *this, void *match_data)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct mdiobus_devres *res = this;
60*4882a593Smuzhiyun struct mii_bus *mii = match_data;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun return mii == res->mii;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun * __devm_mdiobus_register - Resource-managed variant of mdiobus_register()
67*4882a593Smuzhiyun * @dev: Device to register mii_bus for
68*4882a593Smuzhiyun * @bus: MII bus structure to register
69*4882a593Smuzhiyun * @owner: Owning module
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun * Returns 0 on success, negative error number on failure.
72*4882a593Smuzhiyun */
__devm_mdiobus_register(struct device * dev,struct mii_bus * bus,struct module * owner)73*4882a593Smuzhiyun int __devm_mdiobus_register(struct device *dev, struct mii_bus *bus,
74*4882a593Smuzhiyun struct module *owner)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun struct mdiobus_devres *dr;
77*4882a593Smuzhiyun int ret;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (WARN_ON(!devres_find(dev, devm_mdiobus_free,
80*4882a593Smuzhiyun mdiobus_devres_match, bus)))
81*4882a593Smuzhiyun return -EINVAL;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL);
84*4882a593Smuzhiyun if (!dr)
85*4882a593Smuzhiyun return -ENOMEM;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun ret = __mdiobus_register(bus, owner);
88*4882a593Smuzhiyun if (ret) {
89*4882a593Smuzhiyun devres_free(dr);
90*4882a593Smuzhiyun return ret;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun dr->mii = bus;
94*4882a593Smuzhiyun devres_add(dev, dr);
95*4882a593Smuzhiyun return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun EXPORT_SYMBOL(__devm_mdiobus_register);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF_MDIO)
100*4882a593Smuzhiyun /**
101*4882a593Smuzhiyun * devm_of_mdiobus_register - Resource managed variant of of_mdiobus_register()
102*4882a593Smuzhiyun * @dev: Device to register mii_bus for
103*4882a593Smuzhiyun * @mdio: MII bus structure to register
104*4882a593Smuzhiyun * @np: Device node to parse
105*4882a593Smuzhiyun */
devm_of_mdiobus_register(struct device * dev,struct mii_bus * mdio,struct device_node * np)106*4882a593Smuzhiyun int devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio,
107*4882a593Smuzhiyun struct device_node *np)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct mdiobus_devres *dr;
110*4882a593Smuzhiyun int ret;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (WARN_ON(!devres_find(dev, devm_mdiobus_free,
113*4882a593Smuzhiyun mdiobus_devres_match, mdio)))
114*4882a593Smuzhiyun return -EINVAL;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL);
117*4882a593Smuzhiyun if (!dr)
118*4882a593Smuzhiyun return -ENOMEM;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun ret = of_mdiobus_register(mdio, np);
121*4882a593Smuzhiyun if (ret) {
122*4882a593Smuzhiyun devres_free(dr);
123*4882a593Smuzhiyun return ret;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun dr->mii = mdio;
127*4882a593Smuzhiyun devres_add(dev, dr);
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun EXPORT_SYMBOL(devm_of_mdiobus_register);
131*4882a593Smuzhiyun #endif /* CONFIG_OF_MDIO */
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun MODULE_LICENSE("GPL");
134