1
2
3
4
5
6
7#include <common.h>
8#include <dm.h>
9#include <log.h>
10#include <miiphy.h>
11#include <dm/device-internal.h>
12#include <dm/uclass-internal.h>
13#include <dm/lists.h>
14
15#define MDIO_MUX_CHILD_DRV_NAME "mdio-mux-bus-drv"
16
17
18
19
20
21
22
23
24
25struct mdio_mux_perdev_priv {
26 struct udevice *mdio_parent;
27 int selected;
28};
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46struct mdio_mux_ch_data {
47 int sel;
48};
49
50static struct udevice *mmux_get_parent_mdio(struct udevice *mux)
51{
52 struct mdio_mux_perdev_priv *pdata = dev_get_uclass_priv(mux);
53
54 return pdata->mdio_parent;
55}
56
57static struct mdio_ops *mmux_get_mdio_parent_ops(struct udevice *mux)
58{
59 return mdio_get_ops(mmux_get_parent_mdio(mux));
60}
61
62
63static int mmux_change_sel(struct udevice *ch, bool sel)
64{
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);
69 int err = 0;
70
71 if (sel) {
72 err = ops->select(mux, priv->selected, ch_data->sel);
73 if (err)
74 return err;
75
76 priv->selected = ch_data->sel;
77 } else {
78 if (ops->deselect) {
79 ops->deselect(mux, ch_data->sel);
80 priv->selected = MDIO_MUX_SELECT_NONE;
81 }
82 }
83
84 return 0;
85}
86
87
88static int mmux_read(struct udevice *ch, int addr, int devad,
89 int reg)
90{
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);
94 int err;
95
96 err = mmux_change_sel(ch, true);
97 if (err)
98 return err;
99
100 err = parent_ops->read(parent_mdio, addr, devad, reg);
101 mmux_change_sel(ch, false);
102
103 return err;
104}
105
106
107static int mmux_write(struct udevice *ch, int addr, int devad,
108 int reg, u16 val)
109{
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);
113 int err;
114
115 err = mmux_change_sel(ch, true);
116 if (err)
117 return err;
118
119 err = parent_ops->write(parent_mdio, addr, devad, reg, val);
120 mmux_change_sel(ch, false);
121
122 return err;
123}
124
125
126static int mmux_reset(struct udevice *ch)
127{
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);
131 int err;
132
133
134 if (!parent_ops->reset)
135 return 0;
136
137 err = mmux_change_sel(ch, true);
138 if (err)
139 return err;
140
141 err = parent_ops->reset(parent_mdio);
142 mmux_change_sel(ch, false);
143
144 return err;
145}
146
147
148static int dm_mdio_mux_child_post_bind(struct udevice *ch)
149{
150 struct mdio_mux_ch_data *ch_data = dev_get_parent_plat(ch);
151
152 ch_data->sel = dev_read_u32_default(ch, "reg", MDIO_MUX_SELECT_NONE);
153
154 if (ch_data->sel == MDIO_MUX_SELECT_NONE)
155 return -EINVAL;
156
157 return 0;
158}
159
160
161static int dm_mdio_mux_post_bind(struct udevice *mux)
162{
163 ofnode ch_node;
164 int err, first_err = 0;
165
166 if (!dev_has_ofnode(mux)) {
167 debug("%s: no mux node found, no child MDIO busses set up\n",
168 __func__);
169 return 0;
170 }
171
172
173
174
175
176
177 dev_for_each_subnode(ch_node, mux) {
178 struct udevice *ch_dev;
179 const char *ch_name;
180
181 ch_name = ofnode_get_name(ch_node);
182
183 err = device_bind_driver_to_node(mux, MDIO_MUX_CHILD_DRV_NAME,
184 ch_name, ch_node, &ch_dev);
185
186 if (err && !first_err)
187 first_err = err;
188 }
189
190 return first_err;
191}
192
193
194static int dm_mdio_mux_post_probe(struct udevice *mux)
195{
196 struct mdio_mux_perdev_priv *priv = dev_get_uclass_priv(mux);
197 int err;
198
199 priv->selected = MDIO_MUX_SELECT_NONE;
200
201
202 err = uclass_get_device_by_phandle(UCLASS_MDIO, mux, "mdio-parent-bus",
203 &priv->mdio_parent);
204 if (err) {
205 debug("%s: didn't find mdio-parent-bus\n", __func__);
206 return err;
207 }
208
209 return 0;
210}
211
212const struct mdio_ops mmux_child_mdio_ops = {
213 .read = mmux_read,
214 .write = mmux_write,
215 .reset = mmux_reset,
216};
217
218
219U_BOOT_DRIVER(mdio_mux_child) = {
220 .name = MDIO_MUX_CHILD_DRV_NAME,
221 .id = UCLASS_MDIO,
222 .ops = &mmux_child_mdio_ops,
223};
224
225UCLASS_DRIVER(mdio_mux) = {
226 .id = UCLASS_MDIO_MUX,
227 .name = "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),
233};
234