phy: generate swphy registers on the fly
[cascardo/linux.git] / drivers / net / phy / fixed_phy.c
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");