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