xref: /linux/drivers/net/mdio/fwnode_mdio.c (revision d0f482bb06f9447d44d2cae0386a0bd768c3cc16)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * fwnode helpers for the MDIO (Ethernet PHY) API
4  *
5  * This file provides helper functions for extracting PHY device information
6  * out of the fwnode and using it to populate an mii_bus.
7  */
8 
9 #include <linux/acpi.h>
10 #include <linux/acpi_mdio.h>
11 #include <linux/fwnode_mdio.h>
12 #include <linux/of.h>
13 #include <linux/of_mdio.h>
14 #include <linux/phy.h>
15 
16 MODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>");
17 MODULE_LICENSE("GPL");
18 
19 static struct mii_timestamper *
20 fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
21 {
22 	struct of_phandle_args arg;
23 	int err;
24 
25 	if (is_acpi_node(fwnode))
26 		return NULL;
27 
28 	err = of_parse_phandle_with_fixed_args(to_of_node(fwnode),
29 					       "timestamper", 1, 0, &arg);
30 	if (err == -ENOENT)
31 		return NULL;
32 	else if (err)
33 		return ERR_PTR(err);
34 
35 	if (arg.args_count != 1)
36 		return ERR_PTR(-EINVAL);
37 
38 	return register_mii_timestamper(arg.np, arg.args[0]);
39 }
40 
41 int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
42 				       struct phy_device *phy,
43 				       struct fwnode_handle *child, u32 addr)
44 {
45 	int rc;
46 
47 	rc = fwnode_irq_get(child, 0);
48 	if (rc == -EPROBE_DEFER)
49 		return rc;
50 
51 	if (rc > 0) {
52 		phy->irq = rc;
53 		mdio->irq[addr] = rc;
54 	} else {
55 		phy->irq = mdio->irq[addr];
56 	}
57 
58 	if (fwnode_property_read_bool(child, "broken-turn-around"))
59 		mdio->phy_ignore_ta_mask |= 1 << addr;
60 
61 	fwnode_property_read_u32(child, "reset-assert-us",
62 				 &phy->mdio.reset_assert_delay);
63 	fwnode_property_read_u32(child, "reset-deassert-us",
64 				 &phy->mdio.reset_deassert_delay);
65 
66 	/* Associate the fwnode with the device structure so it
67 	 * can be looked up later
68 	 */
69 	fwnode_handle_get(child);
70 	device_set_node(&phy->mdio.dev, child);
71 
72 	/* All data is now stored in the phy struct;
73 	 * register it
74 	 */
75 	rc = phy_device_register(phy);
76 	if (rc) {
77 		fwnode_handle_put(child);
78 		return rc;
79 	}
80 
81 	dev_dbg(&mdio->dev, "registered phy %p fwnode at address %i\n",
82 		child, addr);
83 	return 0;
84 }
85 EXPORT_SYMBOL(fwnode_mdiobus_phy_device_register);
86 
87 int fwnode_mdiobus_register_phy(struct mii_bus *bus,
88 				struct fwnode_handle *child, u32 addr)
89 {
90 	struct mii_timestamper *mii_ts = NULL;
91 	struct phy_device *phy;
92 	bool is_c45 = false;
93 	u32 phy_id;
94 	int rc;
95 
96 	mii_ts = fwnode_find_mii_timestamper(child);
97 	if (IS_ERR(mii_ts))
98 		return PTR_ERR(mii_ts);
99 
100 	rc = fwnode_property_match_string(child, "compatible",
101 					  "ethernet-phy-ieee802.3-c45");
102 	if (rc >= 0)
103 		is_c45 = true;
104 
105 	if (is_c45 || fwnode_get_phy_id(child, &phy_id))
106 		phy = get_phy_device(bus, addr, is_c45);
107 	else
108 		phy = phy_device_create(bus, addr, phy_id, 0, NULL);
109 	if (IS_ERR(phy)) {
110 		unregister_mii_timestamper(mii_ts);
111 		return PTR_ERR(phy);
112 	}
113 
114 	if (is_acpi_node(child)) {
115 		phy->irq = bus->irq[addr];
116 
117 		/* Associate the fwnode with the device structure so it
118 		 * can be looked up later.
119 		 */
120 		phy->mdio.dev.fwnode = child;
121 
122 		/* All data is now stored in the phy struct, so register it */
123 		rc = phy_device_register(phy);
124 		if (rc) {
125 			phy_device_free(phy);
126 			fwnode_handle_put(phy->mdio.dev.fwnode);
127 			return rc;
128 		}
129 	} else if (is_of_node(child)) {
130 		rc = fwnode_mdiobus_phy_device_register(bus, phy, child, addr);
131 		if (rc) {
132 			unregister_mii_timestamper(mii_ts);
133 			phy_device_free(phy);
134 			return rc;
135 		}
136 	}
137 
138 	/* phy->mii_ts may already be defined by the PHY driver. A
139 	 * mii_timestamper probed via the device tree will still have
140 	 * precedence.
141 	 */
142 	if (mii_ts)
143 		phy->mii_ts = mii_ts;
144 	return 0;
145 }
146 EXPORT_SYMBOL(fwnode_mdiobus_register_phy);
147 
148 /**
149  * fwnode_mdiobus_register - bring up all the PHYs on a given MDIO bus and
150  *	attach them to it.
151  * @bus: Target MDIO bus.
152  * @fwnode: Pointer to fwnode of the MDIO controller.
153  *
154  * Return values are determined accordingly to acpi_/of_ mdiobus_register()
155  * operation.
156  */
157 int fwnode_mdiobus_register(struct mii_bus *bus, struct fwnode_handle *fwnode)
158 {
159 	if (is_acpi_node(fwnode))
160 		return acpi_mdiobus_register(bus, fwnode);
161 	else if (is_of_node(fwnode))
162 		return of_mdiobus_register(bus, to_of_node(fwnode));
163 	else
164 		return -EINVAL;
165 }
166 EXPORT_SYMBOL(fwnode_mdiobus_register);
167