]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/phy/fixed_phy.c
9050f21e6f337e5934e1a639e63ad13607574b2d
[karo-tx-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 #define MII_REGS_NUM 29
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         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         int link_gpio;
42 };
43
44 static struct platform_device *pdev;
45 static struct fixed_mdio_bus platform_fmb = {
46         .phys = LIST_HEAD_INIT(platform_fmb.phys),
47 };
48
49 static int fixed_phy_update_regs(struct fixed_phy *fp)
50 {
51         u16 bmsr = BMSR_ANEGCAPABLE;
52         u16 bmcr = 0;
53         u16 lpagb = 0;
54         u16 lpa = 0;
55
56         if (gpio_is_valid(fp->link_gpio))
57                 fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
58
59         if (fp->status.duplex) {
60                 switch (fp->status.speed) {
61                 case 1000:
62                         bmsr |= BMSR_ESTATEN;
63                         break;
64                 case 100:
65                         bmsr |= BMSR_100FULL;
66                         break;
67                 case 10:
68                         bmsr |= BMSR_10FULL;
69                         break;
70                 default:
71                         break;
72                 }
73         } else {
74                 switch (fp->status.speed) {
75                 case 1000:
76                         bmsr |= BMSR_ESTATEN;
77                         break;
78                 case 100:
79                         bmsr |= BMSR_100HALF;
80                         break;
81                 case 10:
82                         bmsr |= BMSR_10HALF;
83                         break;
84                 default:
85                         break;
86                 }
87         }
88
89         if (fp->status.link) {
90                 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
91
92                 if (fp->status.duplex) {
93                         bmcr |= BMCR_FULLDPLX;
94
95                         switch (fp->status.speed) {
96                         case 1000:
97                                 bmcr |= BMCR_SPEED1000;
98                                 lpagb |= LPA_1000FULL;
99                                 break;
100                         case 100:
101                                 bmcr |= BMCR_SPEED100;
102                                 lpa |= LPA_100FULL;
103                                 break;
104                         case 10:
105                                 lpa |= LPA_10FULL;
106                                 break;
107                         default:
108                                 pr_warn("fixed phy: unknown speed\n");
109                                 return -EINVAL;
110                         }
111                 } else {
112                         switch (fp->status.speed) {
113                         case 1000:
114                                 bmcr |= BMCR_SPEED1000;
115                                 lpagb |= LPA_1000HALF;
116                                 break;
117                         case 100:
118                                 bmcr |= BMCR_SPEED100;
119                                 lpa |= LPA_100HALF;
120                                 break;
121                         case 10:
122                                 lpa |= LPA_10HALF;
123                                 break;
124                         default:
125                                 pr_warn("fixed phy: unknown speed\n");
126                         return -EINVAL;
127                         }
128                 }
129
130                 if (fp->status.pause)
131                         lpa |= LPA_PAUSE_CAP;
132
133                 if (fp->status.asym_pause)
134                         lpa |= LPA_PAUSE_ASYM;
135         }
136
137         fp->regs[MII_PHYSID1] = 0;
138         fp->regs[MII_PHYSID2] = 0;
139
140         fp->regs[MII_BMSR] = bmsr;
141         fp->regs[MII_BMCR] = bmcr;
142         fp->regs[MII_LPA] = lpa;
143         fp->regs[MII_STAT1000] = lpagb;
144
145         return 0;
146 }
147
148 static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
149 {
150         struct fixed_mdio_bus *fmb = bus->priv;
151         struct fixed_phy *fp;
152
153         if (reg_num >= MII_REGS_NUM)
154                 return -1;
155
156         /* We do not support emulating Clause 45 over Clause 22 register reads
157          * return an error instead of bogus data.
158          */
159         switch (reg_num) {
160         case MII_MMD_CTRL:
161         case MII_MMD_DATA:
162                 return -1;
163         default:
164                 break;
165         }
166
167         list_for_each_entry(fp, &fmb->phys, node) {
168                 if (fp->addr == phy_addr) {
169                         /* Issue callback if user registered it. */
170                         if (fp->link_update) {
171                                 fp->link_update(fp->phydev->attached_dev,
172                                                 &fp->status);
173                                 fixed_phy_update_regs(fp);
174                         }
175                         return fp->regs[reg_num];
176                 }
177         }
178
179         return 0xFFFF;
180 }
181
182 static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
183                             u16 val)
184 {
185         return 0;
186 }
187
188 /*
189  * If something weird is required to be done with link/speed,
190  * network driver is able to assign a function to implement this.
191  * May be useful for PHY's that need to be software-driven.
192  */
193 int fixed_phy_set_link_update(struct phy_device *phydev,
194                               int (*link_update)(struct net_device *,
195                                                  struct fixed_phy_status *))
196 {
197         struct fixed_mdio_bus *fmb = &platform_fmb;
198         struct fixed_phy *fp;
199
200         if (!phydev || !phydev->mdio.bus)
201                 return -EINVAL;
202
203         list_for_each_entry(fp, &fmb->phys, node) {
204                 if (fp->addr == phydev->mdio.addr) {
205                         fp->link_update = link_update;
206                         fp->phydev = phydev;
207                         return 0;
208                 }
209         }
210
211         return -ENOENT;
212 }
213 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
214
215 int fixed_phy_update_state(struct phy_device *phydev,
216                            const struct fixed_phy_status *status,
217                            const struct fixed_phy_status *changed)
218 {
219         struct fixed_mdio_bus *fmb = &platform_fmb;
220         struct fixed_phy *fp;
221
222         if (!phydev || phydev->mdio.bus != fmb->mii_bus)
223                 return -EINVAL;
224
225         list_for_each_entry(fp, &fmb->phys, node) {
226                 if (fp->addr == phydev->mdio.addr) {
227 #define _UPD(x) if (changed->x) \
228         fp->status.x = status->x
229                         _UPD(link);
230                         _UPD(speed);
231                         _UPD(duplex);
232                         _UPD(pause);
233                         _UPD(asym_pause);
234 #undef _UPD
235                         fixed_phy_update_regs(fp);
236                         return 0;
237                 }
238         }
239
240         return -ENOENT;
241 }
242 EXPORT_SYMBOL(fixed_phy_update_state);
243
244 int fixed_phy_add(unsigned int irq, int phy_addr,
245                   struct fixed_phy_status *status,
246                   int link_gpio)
247 {
248         int ret;
249         struct fixed_mdio_bus *fmb = &platform_fmb;
250         struct fixed_phy *fp;
251
252         fp = kzalloc(sizeof(*fp), GFP_KERNEL);
253         if (!fp)
254                 return -ENOMEM;
255
256         memset(fp->regs, 0xFF,  sizeof(fp->regs[0]) * MII_REGS_NUM);
257
258         fmb->mii_bus->irq[phy_addr] = irq;
259
260         fp->addr = phy_addr;
261         fp->status = *status;
262         fp->link_gpio = link_gpio;
263
264         if (gpio_is_valid(fp->link_gpio)) {
265                 ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN,
266                                        "fixed-link-gpio-link");
267                 if (ret)
268                         goto err_regs;
269         }
270
271         ret = fixed_phy_update_regs(fp);
272         if (ret)
273                 goto err_gpio;
274
275         list_add_tail(&fp->node, &fmb->phys);
276
277         return 0;
278
279 err_gpio:
280         if (gpio_is_valid(fp->link_gpio))
281                 gpio_free(fp->link_gpio);
282 err_regs:
283         kfree(fp);
284         return ret;
285 }
286 EXPORT_SYMBOL_GPL(fixed_phy_add);
287
288 static void fixed_phy_del(int phy_addr)
289 {
290         struct fixed_mdio_bus *fmb = &platform_fmb;
291         struct fixed_phy *fp, *tmp;
292
293         list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
294                 if (fp->addr == phy_addr) {
295                         list_del(&fp->node);
296                         if (gpio_is_valid(fp->link_gpio))
297                                 gpio_free(fp->link_gpio);
298                         kfree(fp);
299                         return;
300                 }
301         }
302 }
303
304 static int phy_fixed_addr;
305 static DEFINE_SPINLOCK(phy_fixed_addr_lock);
306
307 struct phy_device *fixed_phy_register(unsigned int irq,
308                                       struct fixed_phy_status *status,
309                                       int link_gpio,
310                                       struct device_node *np)
311 {
312         struct fixed_mdio_bus *fmb = &platform_fmb;
313         struct phy_device *phy;
314         int phy_addr;
315         int ret;
316
317         /* Get the next available PHY address, up to PHY_MAX_ADDR */
318         spin_lock(&phy_fixed_addr_lock);
319         if (phy_fixed_addr == PHY_MAX_ADDR) {
320                 spin_unlock(&phy_fixed_addr_lock);
321                 return ERR_PTR(-ENOSPC);
322         }
323         phy_addr = phy_fixed_addr++;
324         spin_unlock(&phy_fixed_addr_lock);
325
326         ret = fixed_phy_add(irq, phy_addr, status, link_gpio);
327         if (ret < 0)
328                 return ERR_PTR(ret);
329
330         phy = get_phy_device(fmb->mii_bus, phy_addr, false);
331         if (IS_ERR(phy)) {
332                 fixed_phy_del(phy_addr);
333                 return ERR_PTR(-EINVAL);
334         }
335
336         /* propagate the fixed link values to struct phy_device */
337         phy->link = status->link;
338         if (status->link) {
339                 phy->speed = status->speed;
340                 phy->duplex = status->duplex;
341                 phy->pause = status->pause;
342                 phy->asym_pause = status->asym_pause;
343         }
344
345         of_node_get(np);
346         phy->mdio.dev.of_node = np;
347         phy->is_pseudo_fixed_link = true;
348
349         switch (status->speed) {
350         case SPEED_1000:
351                 phy->supported = PHY_1000BT_FEATURES;
352                 break;
353         case SPEED_100:
354                 phy->supported = PHY_100BT_FEATURES;
355                 break;
356         case SPEED_10:
357         default:
358                 phy->supported = PHY_10BT_FEATURES;
359         }
360
361         ret = phy_device_register(phy);
362         if (ret) {
363                 phy_device_free(phy);
364                 of_node_put(np);
365                 fixed_phy_del(phy_addr);
366                 return ERR_PTR(ret);
367         }
368
369         return phy;
370 }
371 EXPORT_SYMBOL_GPL(fixed_phy_register);
372
373 void fixed_phy_unregister(struct phy_device *phy)
374 {
375         phy_device_remove(phy);
376
377         fixed_phy_del(phy->mdio.addr);
378 }
379 EXPORT_SYMBOL_GPL(fixed_phy_unregister);
380
381 static int __init fixed_mdio_bus_init(void)
382 {
383         struct fixed_mdio_bus *fmb = &platform_fmb;
384         int ret;
385
386         pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
387         if (IS_ERR(pdev)) {
388                 ret = PTR_ERR(pdev);
389                 goto err_pdev;
390         }
391
392         fmb->mii_bus = mdiobus_alloc();
393         if (fmb->mii_bus == NULL) {
394                 ret = -ENOMEM;
395                 goto err_mdiobus_reg;
396         }
397
398         snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
399         fmb->mii_bus->name = "Fixed MDIO Bus";
400         fmb->mii_bus->priv = fmb;
401         fmb->mii_bus->parent = &pdev->dev;
402         fmb->mii_bus->read = &fixed_mdio_read;
403         fmb->mii_bus->write = &fixed_mdio_write;
404
405         ret = mdiobus_register(fmb->mii_bus);
406         if (ret)
407                 goto err_mdiobus_alloc;
408
409         return 0;
410
411 err_mdiobus_alloc:
412         mdiobus_free(fmb->mii_bus);
413 err_mdiobus_reg:
414         platform_device_unregister(pdev);
415 err_pdev:
416         return ret;
417 }
418 module_init(fixed_mdio_bus_init);
419
420 static void __exit fixed_mdio_bus_exit(void)
421 {
422         struct fixed_mdio_bus *fmb = &platform_fmb;
423         struct fixed_phy *fp, *tmp;
424
425         mdiobus_unregister(fmb->mii_bus);
426         mdiobus_free(fmb->mii_bus);
427         platform_device_unregister(pdev);
428
429         list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
430                 list_del(&fp->node);
431                 kfree(fp);
432         }
433 }
434 module_exit(fixed_mdio_bus_exit);
435
436 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
437 MODULE_AUTHOR("Vitaly Bordug");
438 MODULE_LICENSE("GPL");