xref: /openbmc/linux/drivers/net/phy/fixed_phy.c (revision 37688e3f)
1 /*
2  * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
3  *
4  * Author: Vitaly Bordug <vbordug@ru.mvista.com>
5  *         Anton Vorontsov <avorontsov@ru.mvista.com>
6  *
7  * Copyright (c) 2006-2007 MontaVista Software, Inc.
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/list.h>
19 #include <linux/mii.h>
20 #include <linux/phy.h>
21 #include <linux/phy_fixed.h>
22 #include <linux/err.h>
23 #include <linux/slab.h>
24 #include <linux/of.h>
25 #include <linux/gpio.h>
26 
27 #include "swphy.h"
28 
29 struct fixed_mdio_bus {
30 	struct mii_bus *mii_bus;
31 	struct list_head phys;
32 };
33 
34 struct fixed_phy {
35 	int addr;
36 	struct phy_device *phydev;
37 	struct fixed_phy_status status;
38 	int (*link_update)(struct net_device *, struct fixed_phy_status *);
39 	struct list_head node;
40 	int link_gpio;
41 };
42 
43 static struct platform_device *pdev;
44 static struct fixed_mdio_bus platform_fmb = {
45 	.phys = LIST_HEAD_INIT(platform_fmb.phys),
46 };
47 
48 static void fixed_phy_update(struct fixed_phy *fp)
49 {
50 	if (gpio_is_valid(fp->link_gpio))
51 		fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
52 }
53 
54 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
55 {
56 	struct fixed_mdio_bus *fmb = bus->priv;
57 	struct fixed_phy *fp;
58 
59 	list_for_each_entry(fp, &fmb->phys, node) {
60 		if (fp->addr == phy_addr) {
61 			/* Issue callback if user registered it. */
62 			if (fp->link_update) {
63 				fp->link_update(fp->phydev->attached_dev,
64 						&fp->status);
65 				fixed_phy_update(fp);
66 			}
67 			return swphy_read_reg(reg_num, &fp->status);
68 		}
69 	}
70 
71 	return 0xFFFF;
72 }
73 
74 static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
75 			    u16 val)
76 {
77 	return 0;
78 }
79 
80 /*
81  * If something weird is required to be done with link/speed,
82  * network driver is able to assign a function to implement this.
83  * May be useful for PHY's that need to be software-driven.
84  */
85 int fixed_phy_set_link_update(struct phy_device *phydev,
86 			      int (*link_update)(struct net_device *,
87 						 struct fixed_phy_status *))
88 {
89 	struct fixed_mdio_bus *fmb = &platform_fmb;
90 	struct fixed_phy *fp;
91 
92 	if (!phydev || !phydev->mdio.bus)
93 		return -EINVAL;
94 
95 	list_for_each_entry(fp, &fmb->phys, node) {
96 		if (fp->addr == phydev->mdio.addr) {
97 			fp->link_update = link_update;
98 			fp->phydev = phydev;
99 			return 0;
100 		}
101 	}
102 
103 	return -ENOENT;
104 }
105 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
106 
107 int fixed_phy_update_state(struct phy_device *phydev,
108 			   const struct fixed_phy_status *status,
109 			   const struct fixed_phy_status *changed)
110 {
111 	struct fixed_mdio_bus *fmb = &platform_fmb;
112 	struct fixed_phy *fp;
113 
114 	if (!phydev || phydev->mdio.bus != fmb->mii_bus)
115 		return -EINVAL;
116 
117 	list_for_each_entry(fp, &fmb->phys, node) {
118 		if (fp->addr == phydev->mdio.addr) {
119 #define _UPD(x) if (changed->x) \
120 	fp->status.x = status->x
121 			_UPD(link);
122 			_UPD(speed);
123 			_UPD(duplex);
124 			_UPD(pause);
125 			_UPD(asym_pause);
126 #undef _UPD
127 			fixed_phy_update(fp);
128 			return 0;
129 		}
130 	}
131 
132 	return -ENOENT;
133 }
134 EXPORT_SYMBOL(fixed_phy_update_state);
135 
136 int fixed_phy_add(unsigned int irq, int phy_addr,
137 		  struct fixed_phy_status *status,
138 		  int link_gpio)
139 {
140 	int ret;
141 	struct fixed_mdio_bus *fmb = &platform_fmb;
142 	struct fixed_phy *fp;
143 
144 	ret = swphy_validate_state(status);
145 	if (ret < 0)
146 		return ret;
147 
148 	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
149 	if (!fp)
150 		return -ENOMEM;
151 
152 	if (irq != PHY_POLL)
153 		fmb->mii_bus->irq[phy_addr] = irq;
154 
155 	fp->addr = phy_addr;
156 	fp->status = *status;
157 	fp->link_gpio = link_gpio;
158 
159 	if (gpio_is_valid(fp->link_gpio)) {
160 		ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN,
161 				       "fixed-link-gpio-link");
162 		if (ret)
163 			goto err_regs;
164 	}
165 
166 	fixed_phy_update(fp);
167 
168 	list_add_tail(&fp->node, &fmb->phys);
169 
170 	return 0;
171 
172 err_regs:
173 	kfree(fp);
174 	return ret;
175 }
176 EXPORT_SYMBOL_GPL(fixed_phy_add);
177 
178 static void fixed_phy_del(int phy_addr)
179 {
180 	struct fixed_mdio_bus *fmb = &platform_fmb;
181 	struct fixed_phy *fp, *tmp;
182 
183 	list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
184 		if (fp->addr == phy_addr) {
185 			list_del(&fp->node);
186 			if (gpio_is_valid(fp->link_gpio))
187 				gpio_free(fp->link_gpio);
188 			kfree(fp);
189 			return;
190 		}
191 	}
192 }
193 
194 static int phy_fixed_addr;
195 static DEFINE_SPINLOCK(phy_fixed_addr_lock);
196 
197 struct phy_device *fixed_phy_register(unsigned int irq,
198 				      struct fixed_phy_status *status,
199 				      int link_gpio,
200 				      struct device_node *np)
201 {
202 	struct fixed_mdio_bus *fmb = &platform_fmb;
203 	struct phy_device *phy;
204 	int phy_addr;
205 	int ret;
206 
207 	if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED)
208 		return ERR_PTR(-EPROBE_DEFER);
209 
210 	/* Get the next available PHY address, up to PHY_MAX_ADDR */
211 	spin_lock(&phy_fixed_addr_lock);
212 	if (phy_fixed_addr == PHY_MAX_ADDR) {
213 		spin_unlock(&phy_fixed_addr_lock);
214 		return ERR_PTR(-ENOSPC);
215 	}
216 	phy_addr = phy_fixed_addr++;
217 	spin_unlock(&phy_fixed_addr_lock);
218 
219 	ret = fixed_phy_add(irq, phy_addr, status, link_gpio);
220 	if (ret < 0)
221 		return ERR_PTR(ret);
222 
223 	phy = get_phy_device(fmb->mii_bus, phy_addr, false);
224 	if (IS_ERR(phy)) {
225 		fixed_phy_del(phy_addr);
226 		return ERR_PTR(-EINVAL);
227 	}
228 
229 	/* propagate the fixed link values to struct phy_device */
230 	phy->link = status->link;
231 	if (status->link) {
232 		phy->speed = status->speed;
233 		phy->duplex = status->duplex;
234 		phy->pause = status->pause;
235 		phy->asym_pause = status->asym_pause;
236 	}
237 
238 	of_node_get(np);
239 	phy->mdio.dev.of_node = np;
240 	phy->is_pseudo_fixed_link = true;
241 
242 	switch (status->speed) {
243 	case SPEED_1000:
244 		phy->supported = PHY_1000BT_FEATURES;
245 		break;
246 	case SPEED_100:
247 		phy->supported = PHY_100BT_FEATURES;
248 		break;
249 	case SPEED_10:
250 	default:
251 		phy->supported = PHY_10BT_FEATURES;
252 	}
253 
254 	ret = phy_device_register(phy);
255 	if (ret) {
256 		phy_device_free(phy);
257 		of_node_put(np);
258 		fixed_phy_del(phy_addr);
259 		return ERR_PTR(ret);
260 	}
261 
262 	return phy;
263 }
264 EXPORT_SYMBOL_GPL(fixed_phy_register);
265 
266 void fixed_phy_unregister(struct phy_device *phy)
267 {
268 	phy_device_remove(phy);
269 
270 	fixed_phy_del(phy->mdio.addr);
271 }
272 EXPORT_SYMBOL_GPL(fixed_phy_unregister);
273 
274 static int __init fixed_mdio_bus_init(void)
275 {
276 	struct fixed_mdio_bus *fmb = &platform_fmb;
277 	int ret;
278 
279 	pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
280 	if (IS_ERR(pdev)) {
281 		ret = PTR_ERR(pdev);
282 		goto err_pdev;
283 	}
284 
285 	fmb->mii_bus = mdiobus_alloc();
286 	if (fmb->mii_bus == NULL) {
287 		ret = -ENOMEM;
288 		goto err_mdiobus_reg;
289 	}
290 
291 	snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
292 	fmb->mii_bus->name = "Fixed MDIO Bus";
293 	fmb->mii_bus->priv = fmb;
294 	fmb->mii_bus->parent = &pdev->dev;
295 	fmb->mii_bus->read = &fixed_mdio_read;
296 	fmb->mii_bus->write = &fixed_mdio_write;
297 
298 	ret = mdiobus_register(fmb->mii_bus);
299 	if (ret)
300 		goto err_mdiobus_alloc;
301 
302 	return 0;
303 
304 err_mdiobus_alloc:
305 	mdiobus_free(fmb->mii_bus);
306 err_mdiobus_reg:
307 	platform_device_unregister(pdev);
308 err_pdev:
309 	return ret;
310 }
311 module_init(fixed_mdio_bus_init);
312 
313 static void __exit fixed_mdio_bus_exit(void)
314 {
315 	struct fixed_mdio_bus *fmb = &platform_fmb;
316 	struct fixed_phy *fp, *tmp;
317 
318 	mdiobus_unregister(fmb->mii_bus);
319 	mdiobus_free(fmb->mii_bus);
320 	platform_device_unregister(pdev);
321 
322 	list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
323 		list_del(&fp->node);
324 		kfree(fp);
325 	}
326 }
327 module_exit(fixed_mdio_bus_exit);
328 
329 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
330 MODULE_AUTHOR("Vitaly Bordug");
331 MODULE_LICENSE("GPL");
332