xref: /openbmc/linux/drivers/net/phy/mdio_devres.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
18b11c20aSBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0-or-later
28b11c20aSBartosz Golaszewski 
3ac3a68d5SBartosz Golaszewski #include <linux/device.h>
414eeb6e0SBartosz Golaszewski #include <linux/of_mdio.h>
58b11c20aSBartosz Golaszewski #include <linux/phy.h>
6ac3a68d5SBartosz Golaszewski #include <linux/stddef.h>
7ac3a68d5SBartosz Golaszewski 
8ac3a68d5SBartosz Golaszewski struct mdiobus_devres {
9ac3a68d5SBartosz Golaszewski 	struct mii_bus *mii;
10ac3a68d5SBartosz Golaszewski };
11ac3a68d5SBartosz Golaszewski 
devm_mdiobus_free(struct device * dev,void * this)12ac3a68d5SBartosz Golaszewski static void devm_mdiobus_free(struct device *dev, void *this)
13ac3a68d5SBartosz Golaszewski {
14ac3a68d5SBartosz Golaszewski 	struct mdiobus_devres *dr = this;
15ac3a68d5SBartosz Golaszewski 
16ac3a68d5SBartosz Golaszewski 	mdiobus_free(dr->mii);
17ac3a68d5SBartosz Golaszewski }
18ac3a68d5SBartosz Golaszewski 
19ac3a68d5SBartosz Golaszewski /**
20ac3a68d5SBartosz Golaszewski  * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size()
21ac3a68d5SBartosz Golaszewski  * @dev:		Device to allocate mii_bus for
22ac3a68d5SBartosz Golaszewski  * @sizeof_priv:	Space to allocate for private structure
23ac3a68d5SBartosz Golaszewski  *
24ac3a68d5SBartosz Golaszewski  * Managed mdiobus_alloc_size. mii_bus allocated with this function is
25ac3a68d5SBartosz Golaszewski  * automatically freed on driver detach.
26ac3a68d5SBartosz Golaszewski  *
27ac3a68d5SBartosz Golaszewski  * RETURNS:
28ac3a68d5SBartosz Golaszewski  * Pointer to allocated mii_bus on success, NULL on out-of-memory error.
29ac3a68d5SBartosz Golaszewski  */
devm_mdiobus_alloc_size(struct device * dev,int sizeof_priv)30ac3a68d5SBartosz Golaszewski struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv)
31ac3a68d5SBartosz Golaszewski {
32ac3a68d5SBartosz Golaszewski 	struct mdiobus_devres *dr;
33ac3a68d5SBartosz Golaszewski 
34ac3a68d5SBartosz Golaszewski 	dr = devres_alloc(devm_mdiobus_free, sizeof(*dr), GFP_KERNEL);
35ac3a68d5SBartosz Golaszewski 	if (!dr)
36ac3a68d5SBartosz Golaszewski 		return NULL;
37ac3a68d5SBartosz Golaszewski 
38ac3a68d5SBartosz Golaszewski 	dr->mii = mdiobus_alloc_size(sizeof_priv);
39ac3a68d5SBartosz Golaszewski 	if (!dr->mii) {
40ac3a68d5SBartosz Golaszewski 		devres_free(dr);
41ac3a68d5SBartosz Golaszewski 		return NULL;
42ac3a68d5SBartosz Golaszewski 	}
43ac3a68d5SBartosz Golaszewski 
44ac3a68d5SBartosz Golaszewski 	devres_add(dev, dr);
45ac3a68d5SBartosz Golaszewski 	return dr->mii;
46ac3a68d5SBartosz Golaszewski }
47ac3a68d5SBartosz Golaszewski EXPORT_SYMBOL(devm_mdiobus_alloc_size);
48ac3a68d5SBartosz Golaszewski 
devm_mdiobus_unregister(struct device * dev,void * this)49ac3a68d5SBartosz Golaszewski static void devm_mdiobus_unregister(struct device *dev, void *this)
50ac3a68d5SBartosz Golaszewski {
51ac3a68d5SBartosz Golaszewski 	struct mdiobus_devres *dr = this;
52ac3a68d5SBartosz Golaszewski 
53ac3a68d5SBartosz Golaszewski 	mdiobus_unregister(dr->mii);
54ac3a68d5SBartosz Golaszewski }
55ac3a68d5SBartosz Golaszewski 
mdiobus_devres_match(struct device * dev,void * this,void * match_data)56ac3a68d5SBartosz Golaszewski static int mdiobus_devres_match(struct device *dev,
57ac3a68d5SBartosz Golaszewski 				void *this, void *match_data)
58ac3a68d5SBartosz Golaszewski {
59ac3a68d5SBartosz Golaszewski 	struct mdiobus_devres *res = this;
60ac3a68d5SBartosz Golaszewski 	struct mii_bus *mii = match_data;
61ac3a68d5SBartosz Golaszewski 
62ac3a68d5SBartosz Golaszewski 	return mii == res->mii;
63ac3a68d5SBartosz Golaszewski }
648b11c20aSBartosz Golaszewski 
656a9a5723SBartosz Golaszewski /**
666a9a5723SBartosz Golaszewski  * __devm_mdiobus_register - Resource-managed variant of mdiobus_register()
67ac3a68d5SBartosz Golaszewski  * @dev:	Device to register mii_bus for
686a9a5723SBartosz Golaszewski  * @bus:	MII bus structure to register
696a9a5723SBartosz Golaszewski  * @owner:	Owning module
706a9a5723SBartosz Golaszewski  *
716a9a5723SBartosz Golaszewski  * Returns 0 on success, negative error number on failure.
726a9a5723SBartosz Golaszewski  */
__devm_mdiobus_register(struct device * dev,struct mii_bus * bus,struct module * owner)73ac3a68d5SBartosz Golaszewski int __devm_mdiobus_register(struct device *dev, struct mii_bus *bus,
74ac3a68d5SBartosz Golaszewski 			    struct module *owner)
758b11c20aSBartosz Golaszewski {
76ac3a68d5SBartosz Golaszewski 	struct mdiobus_devres *dr;
778b11c20aSBartosz Golaszewski 	int ret;
788b11c20aSBartosz Golaszewski 
79ac3a68d5SBartosz Golaszewski 	if (WARN_ON(!devres_find(dev, devm_mdiobus_free,
80ac3a68d5SBartosz Golaszewski 				 mdiobus_devres_match, bus)))
81ac3a68d5SBartosz Golaszewski 		return -EINVAL;
82ac3a68d5SBartosz Golaszewski 
83ac3a68d5SBartosz Golaszewski 	dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL);
84ac3a68d5SBartosz Golaszewski 	if (!dr)
85ac3a68d5SBartosz Golaszewski 		return -ENOMEM;
868b11c20aSBartosz Golaszewski 
878b11c20aSBartosz Golaszewski 	ret = __mdiobus_register(bus, owner);
88ac3a68d5SBartosz Golaszewski 	if (ret) {
89ac3a68d5SBartosz Golaszewski 		devres_free(dr);
908b11c20aSBartosz Golaszewski 		return ret;
918b11c20aSBartosz Golaszewski 	}
92ac3a68d5SBartosz Golaszewski 
93ac3a68d5SBartosz Golaszewski 	dr->mii = bus;
94ac3a68d5SBartosz Golaszewski 	devres_add(dev, dr);
95ac3a68d5SBartosz Golaszewski 	return 0;
96ac3a68d5SBartosz Golaszewski }
978b11c20aSBartosz Golaszewski EXPORT_SYMBOL(__devm_mdiobus_register);
9814eeb6e0SBartosz Golaszewski 
9914eeb6e0SBartosz Golaszewski #if IS_ENABLED(CONFIG_OF_MDIO)
10014eeb6e0SBartosz Golaszewski /**
101*99669259SMaxime Bizon  * __devm_of_mdiobus_register - Resource managed variant of of_mdiobus_register()
10214eeb6e0SBartosz Golaszewski  * @dev:	Device to register mii_bus for
10314eeb6e0SBartosz Golaszewski  * @mdio:	MII bus structure to register
10414eeb6e0SBartosz Golaszewski  * @np:		Device node to parse
105*99669259SMaxime Bizon  * @owner:	Owning module
10614eeb6e0SBartosz Golaszewski  */
__devm_of_mdiobus_register(struct device * dev,struct mii_bus * mdio,struct device_node * np,struct module * owner)107*99669259SMaxime Bizon int __devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio,
108*99669259SMaxime Bizon 			       struct device_node *np, struct module *owner)
10914eeb6e0SBartosz Golaszewski {
11014eeb6e0SBartosz Golaszewski 	struct mdiobus_devres *dr;
11114eeb6e0SBartosz Golaszewski 	int ret;
11214eeb6e0SBartosz Golaszewski 
11314eeb6e0SBartosz Golaszewski 	if (WARN_ON(!devres_find(dev, devm_mdiobus_free,
11414eeb6e0SBartosz Golaszewski 				 mdiobus_devres_match, mdio)))
11514eeb6e0SBartosz Golaszewski 		return -EINVAL;
11614eeb6e0SBartosz Golaszewski 
11714eeb6e0SBartosz Golaszewski 	dr = devres_alloc(devm_mdiobus_unregister, sizeof(*dr), GFP_KERNEL);
11814eeb6e0SBartosz Golaszewski 	if (!dr)
11914eeb6e0SBartosz Golaszewski 		return -ENOMEM;
12014eeb6e0SBartosz Golaszewski 
121*99669259SMaxime Bizon 	ret = __of_mdiobus_register(mdio, np, owner);
12214eeb6e0SBartosz Golaszewski 	if (ret) {
12314eeb6e0SBartosz Golaszewski 		devres_free(dr);
12414eeb6e0SBartosz Golaszewski 		return ret;
12514eeb6e0SBartosz Golaszewski 	}
12614eeb6e0SBartosz Golaszewski 
12714eeb6e0SBartosz Golaszewski 	dr->mii = mdio;
12814eeb6e0SBartosz Golaszewski 	devres_add(dev, dr);
12914eeb6e0SBartosz Golaszewski 	return 0;
13014eeb6e0SBartosz Golaszewski }
131*99669259SMaxime Bizon EXPORT_SYMBOL(__devm_of_mdiobus_register);
13214eeb6e0SBartosz Golaszewski #endif /* CONFIG_OF_MDIO */
13314eeb6e0SBartosz Golaszewski 
13414eeb6e0SBartosz Golaszewski MODULE_LICENSE("GPL");
135