1 // SPDX-License-Identifier: GPL-2.0+
11 #include <dm/device-internal.h>
12 #include <dm/uclass-internal.h>
15 #define MDIO_MUX_CHILD_DRV_NAME "mdio-mux-bus-drv"
18 * struct mdio_mux_perdev_priv - Per-device class data for MDIO MUX DM
20 * @parent_mdio: Parent DM MDIO device, this is called for actual MDIO I/O after
21 * setting up the mux. Typically this is a real MDIO device,
22 * unless there are cascaded muxes.
23 * @selected: Current child bus selection. Defaults to -1
25 struct mdio_mux_perdev_priv {
26 struct udevice *mdio_parent;
31 * This source file uses three types of devices, as follows:
32 * - mux is the hardware MDIO MUX which selects between the existing child MDIO
33 * buses, this is the device relevant for MDIO MUX class of drivers.
34 * - ch is a child MDIO bus, this is just a representation of a mux selection,
35 * not a real piece of hardware.
36 * - mdio_parent is the actual MDIO bus called to perform reads/writes after
37 * the MUX is configured. Typically this is a real MDIO device, unless there
42 * struct mdio_mux_ch_data - Per-device data for child MDIOs
44 * @sel: Selection value used by the MDIO MUX to access this child MDIO bus
46 struct mdio_mux_ch_data {
50 static struct udevice *mmux_get_parent_mdio(struct udevice *mux)
52 struct mdio_mux_perdev_priv *pdata = dev_get_uclass_priv(mux);
54 return pdata->mdio_parent;
57 static struct mdio_ops *mmux_get_mdio_parent_ops(struct udevice *mux)
59 return mdio_get_ops(mmux_get_parent_mdio(mux));
62 /* call driver select function before performing MDIO r/w */
63 static int mmux_change_sel(struct udevice *ch, bool sel)
65 struct udevice *mux = ch->parent;
66 struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
67 struct mdio_mux_ops *ops = mdio_mux_get_ops(mux);
68 struct mdio_mux_ch_data *ch_data = dev_get_parent_plat(ch);
72 err = ops->select(mux, priv->selected, ch_data->sel);
76 priv->selected = ch_data->sel;
79 ops->deselect(mux, ch_data->sel);
80 priv->selected = MDIO_MUX_SELECT_NONE;
87 /* Read wrapper, sets up the mux before issuing a read on parent MDIO bus */
88 static int mmux_read(struct udevice *ch, int addr, int devad,
91 struct udevice *mux = ch->parent;
92 struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
93 struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
96 err = mmux_change_sel(ch, true);
100 err = parent_ops->read(parent_mdio, addr, devad, reg);
101 mmux_change_sel(ch, false);
106 /* Write wrapper, sets up the mux before issuing a write on parent MDIO bus */
107 static int mmux_write(struct udevice *ch, int addr, int devad,
110 struct udevice *mux = ch->parent;
111 struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
112 struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
115 err = mmux_change_sel(ch, true);
119 err = parent_ops->write(parent_mdio, addr, devad, reg, val);
120 mmux_change_sel(ch, false);
125 /* Reset wrapper, sets up the mux before issuing a reset on parent MDIO bus */
126 static int mmux_reset(struct udevice *ch)
128 struct udevice *mux = ch->parent;
129 struct udevice *parent_mdio = mmux_get_parent_mdio(mux);
130 struct mdio_ops *parent_ops = mmux_get_mdio_parent_ops(mux);
133 /* reset is optional, if it's not implemented just exit */
134 if (!parent_ops->reset)
137 err = mmux_change_sel(ch, true);
141 err = parent_ops->reset(parent_mdio);
142 mmux_change_sel(ch, false);
147 /* Picks up the mux selection value for each child */
148 static int dm_mdio_mux_child_post_bind(struct udevice *ch)
150 struct mdio_mux_ch_data *ch_data = dev_get_parent_plat(ch);
152 ch_data->sel = dev_read_u32_default(ch, "reg", MDIO_MUX_SELECT_NONE);
154 if (ch_data->sel == MDIO_MUX_SELECT_NONE)
160 /* Explicitly bind child MDIOs after binding the mux */
161 static int dm_mdio_mux_post_bind(struct udevice *mux)
164 int err, first_err = 0;
166 if (!dev_has_ofnode(mux)) {
167 debug("%s: no mux node found, no child MDIO busses set up\n",
173 * we're going by Linux bindings so the child nodes do not have
174 * compatible strings. We're going through them here and binding to
177 dev_for_each_subnode(ch_node, mux) {
178 struct udevice *ch_dev;
181 ch_name = ofnode_get_name(ch_node);
183 err = device_bind_driver_to_node(mux, MDIO_MUX_CHILD_DRV_NAME,
184 ch_name, ch_node, &ch_dev);
185 /* try to bind all, but keep 1st error */
186 if (err && !first_err)
193 /* Get a reference to the parent MDIO bus, it should be bound by now */
194 static int dm_mdio_mux_post_probe(struct udevice *mux)
196 struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
199 priv->selected = MDIO_MUX_SELECT_NONE;
201 /* pick up mdio parent from device tree */
202 err = uclass_get_device_by_phandle(UCLASS_MDIO, mux, "mdio-parent-bus",
205 debug("%s: didn't find mdio-parent-bus\n", __func__);
212 const struct mdio_ops mmux_child_mdio_ops = {
218 /* MDIO class driver used for MUX child MDIO buses */
219 U_BOOT_DRIVER(mdio_mux_child) = {
220 .name = MDIO_MUX_CHILD_DRV_NAME,
222 .ops = &mmux_child_mdio_ops,
225 UCLASS_DRIVER(mdio_mux) = {
226 .id = UCLASS_MDIO_MUX,
228 .child_post_bind = dm_mdio_mux_child_post_bind,
229 .post_bind = dm_mdio_mux_post_bind,
230 .post_probe = dm_mdio_mux_post_probe,
231 .per_device_auto = sizeof(struct mdio_mux_perdev_priv),
232 .per_child_plat_auto = sizeof(struct mdio_mux_ch_data),