net: Allow FIXED_PHY to be modular.
[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
26 #define MII_REGS_NUM 29
27
28 struct fixed_mdio_bus {
29         int irqs[PHY_MAX_ADDR];
30         struct mii_bus *mii_bus;
31         struct list_head phys;
32 };
33
34 struct fixed_phy {
35         int addr;
36         u16 regs[MII_REGS_NUM];
37         struct phy_device *phydev;
38         struct fixed_phy_status status;
39         int (*link_update)(struct net_device *, struct fixed_phy_status *);
40         struct list_head node;
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 int fixed_phy_update_regs(struct fixed_phy *fp)
49 {
50         u16 bmsr = BMSR_ANEGCAPABLE;
51         u16 bmcr = 0;
52         u16 lpagb = 0;
53         u16 lpa = 0;
54
55         if (fp->status.duplex) {
56                 bmcr |= BMCR_FULLDPLX;
57
58                 switch (fp->status.speed) {
59                 case 1000:
60                         bmsr |= BMSR_ESTATEN;
61                         bmcr |= BMCR_SPEED1000;
62                         lpagb |= LPA_1000FULL;
63                         break;
64                 case 100:
65                         bmsr |= BMSR_100FULL;
66                         bmcr |= BMCR_SPEED100;
67                         lpa |= LPA_100FULL;
68                         break;
69                 case 10:
70                         bmsr |= BMSR_10FULL;
71                         lpa |= LPA_10FULL;
72                         break;
73                 default:
74                         pr_warn("fixed phy: unknown speed\n");
75                         return -EINVAL;
76                 }
77         } else {
78                 switch (fp->status.speed) {
79                 case 1000:
80                         bmsr |= BMSR_ESTATEN;
81                         bmcr |= BMCR_SPEED1000;
82                         lpagb |= LPA_1000HALF;
83                         break;
84                 case 100:
85                         bmsr |= BMSR_100HALF;
86                         bmcr |= BMCR_SPEED100;
87                         lpa |= LPA_100HALF;
88                         break;
89                 case 10:
90                         bmsr |= BMSR_10HALF;
91                         lpa |= LPA_10HALF;
92                         break;
93                 default:
94                         pr_warn("fixed phy: unknown speed\n");
95                         return -EINVAL;
96                 }
97         }
98
99         if (fp->status.link)
100                 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
101
102         if (fp->status.pause)
103                 lpa |= LPA_PAUSE_CAP;
104
105         if (fp->status.asym_pause)
106                 lpa |= LPA_PAUSE_ASYM;
107
108         fp->regs[MII_PHYSID1] = 0;
109         fp->regs[MII_PHYSID2] = 0;
110
111         fp->regs[MII_BMSR] = bmsr;
112         fp->regs[MII_BMCR] = bmcr;
113         fp->regs[MII_LPA] = lpa;
114         fp->regs[MII_STAT1000] = lpagb;
115
116         return 0;
117 }
118
119 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
120 {
121         struct fixed_mdio_bus *fmb = bus->priv;
122         struct fixed_phy *fp;
123
124         if (reg_num >= MII_REGS_NUM)
125                 return -1;
126
127         /* We do not support emulating Clause 45 over Clause 22 register reads
128          * return an error instead of bogus data.
129          */
130         switch (reg_num) {
131         case MII_MMD_CTRL:
132         case MII_MMD_DATA:
133                 return -1;
134         default:
135                 break;
136         }
137
138         list_for_each_entry(fp, &fmb->phys, node) {
139                 if (fp->addr == phy_addr) {
140                         /* Issue callback if user registered it. */
141                         if (fp->link_update) {
142                                 fp->link_update(fp->phydev->attached_dev,
143                                                 &fp->status);
144                                 fixed_phy_update_regs(fp);
145                         }
146                         return fp->regs[reg_num];
147                 }
148         }
149
150         return 0xFFFF;
151 }
152
153 static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
154                             u16 val)
155 {
156         return 0;
157 }
158
159 /*
160  * If something weird is required to be done with link/speed,
161  * network driver is able to assign a function to implement this.
162  * May be useful for PHY's that need to be software-driven.
163  */
164 int fixed_phy_set_link_update(struct phy_device *phydev,
165                               int (*link_update)(struct net_device *,
166                                                  struct fixed_phy_status *))
167 {
168         struct fixed_mdio_bus *fmb = &platform_fmb;
169         struct fixed_phy *fp;
170
171         if (!link_update || !phydev || !phydev->bus)
172                 return -EINVAL;
173
174         list_for_each_entry(fp, &fmb->phys, node) {
175                 if (fp->addr == phydev->addr) {
176                         fp->link_update = link_update;
177                         fp->phydev = phydev;
178                         return 0;
179                 }
180         }
181
182         return -ENOENT;
183 }
184 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
185
186 int fixed_phy_add(unsigned int irq, int phy_addr,
187                   struct fixed_phy_status *status)
188 {
189         int ret;
190         struct fixed_mdio_bus *fmb = &platform_fmb;
191         struct fixed_phy *fp;
192
193         fp = kzalloc(sizeof(*fp), GFP_KERNEL);
194         if (!fp)
195                 return -ENOMEM;
196
197         memset(fp->regs, 0xFF,  sizeof(fp->regs[0]) * MII_REGS_NUM);
198
199         fmb->irqs[phy_addr] = irq;
200
201         fp->addr = phy_addr;
202         fp->status = *status;
203
204         ret = fixed_phy_update_regs(fp);
205         if (ret)
206                 goto err_regs;
207
208         list_add_tail(&fp->node, &fmb->phys);
209
210         return 0;
211
212 err_regs:
213         kfree(fp);
214         return ret;
215 }
216 EXPORT_SYMBOL_GPL(fixed_phy_add);
217
218 void fixed_phy_del(int phy_addr)
219 {
220         struct fixed_mdio_bus *fmb = &platform_fmb;
221         struct fixed_phy *fp, *tmp;
222
223         list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
224                 if (fp->addr == phy_addr) {
225                         list_del(&fp->node);
226                         kfree(fp);
227                         return;
228                 }
229         }
230 }
231 EXPORT_SYMBOL_GPL(fixed_phy_del);
232
233 static int phy_fixed_addr;
234 static DEFINE_SPINLOCK(phy_fixed_addr_lock);
235
236 struct phy_device *fixed_phy_register(unsigned int irq,
237                                       struct fixed_phy_status *status,
238                                       struct device_node *np)
239 {
240         struct fixed_mdio_bus *fmb = &platform_fmb;
241         struct phy_device *phy;
242         int phy_addr;
243         int ret;
244
245         /* Get the next available PHY address, up to PHY_MAX_ADDR */
246         spin_lock(&phy_fixed_addr_lock);
247         if (phy_fixed_addr == PHY_MAX_ADDR) {
248                 spin_unlock(&phy_fixed_addr_lock);
249                 return ERR_PTR(-ENOSPC);
250         }
251         phy_addr = phy_fixed_addr++;
252         spin_unlock(&phy_fixed_addr_lock);
253
254         ret = fixed_phy_add(PHY_POLL, phy_addr, status);
255         if (ret < 0)
256                 return ERR_PTR(ret);
257
258         phy = get_phy_device(fmb->mii_bus, phy_addr, false);
259         if (!phy || IS_ERR(phy)) {
260                 fixed_phy_del(phy_addr);
261                 return ERR_PTR(-EINVAL);
262         }
263
264         of_node_get(np);
265         phy->dev.of_node = np;
266
267         ret = phy_device_register(phy);
268         if (ret) {
269                 phy_device_free(phy);
270                 of_node_put(np);
271                 fixed_phy_del(phy_addr);
272                 return ERR_PTR(ret);
273         }
274
275         return phy;
276 }
277 EXPORT_SYMBOL_GPL(fixed_phy_register);
278
279 static int __init fixed_mdio_bus_init(void)
280 {
281         struct fixed_mdio_bus *fmb = &platform_fmb;
282         int ret;
283
284         pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
285         if (IS_ERR(pdev)) {
286                 ret = PTR_ERR(pdev);
287                 goto err_pdev;
288         }
289
290         fmb->mii_bus = mdiobus_alloc();
291         if (fmb->mii_bus == NULL) {
292                 ret = -ENOMEM;
293                 goto err_mdiobus_reg;
294         }
295
296         snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
297         fmb->mii_bus->name = "Fixed MDIO Bus";
298         fmb->mii_bus->priv = fmb;
299         fmb->mii_bus->parent = &pdev->dev;
300         fmb->mii_bus->read = &fixed_mdio_read;
301         fmb->mii_bus->write = &fixed_mdio_write;
302         fmb->mii_bus->irq = fmb->irqs;
303
304         ret = mdiobus_register(fmb->mii_bus);
305         if (ret)
306                 goto err_mdiobus_alloc;
307
308         return 0;
309
310 err_mdiobus_alloc:
311         mdiobus_free(fmb->mii_bus);
312 err_mdiobus_reg:
313         platform_device_unregister(pdev);
314 err_pdev:
315         return ret;
316 }
317 module_init(fixed_mdio_bus_init);
318
319 static void __exit fixed_mdio_bus_exit(void)
320 {
321         struct fixed_mdio_bus *fmb = &platform_fmb;
322         struct fixed_phy *fp, *tmp;
323
324         mdiobus_unregister(fmb->mii_bus);
325         mdiobus_free(fmb->mii_bus);
326         platform_device_unregister(pdev);
327
328         list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
329                 list_del(&fp->node);
330                 kfree(fp);
331         }
332 }
333 module_exit(fixed_mdio_bus_exit);
334
335 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
336 MODULE_AUTHOR("Vitaly Bordug");
337 MODULE_LICENSE("GPL");