Upstream refresh for v1.5.0-rc1 : Upstream 19.07 : 4fb6b8c553f692eeb5bcb203e0f8ee8df0...
[librecmc/librecmc.git] / target / linux / ath79 / files / drivers / net / ethernet / atheros / ag71xx / ag71xx_phy.c
1 /*
2  *  Atheros AR71xx built-in ethernet mac driver
3  *
4  *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
5  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6  *
7  *  Based on Atheros' AG7100 driver
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 version 2 as published
11  *  by the Free Software Foundation.
12  */
13
14 #include <linux/of_mdio.h>
15 #include "ag71xx.h"
16
17 static void ag71xx_phy_link_adjust(struct net_device *dev)
18 {
19         struct ag71xx *ag = netdev_priv(dev);
20         struct phy_device *phydev = ag->phy_dev;
21         unsigned long flags;
22         int status_change = 0;
23
24         spin_lock_irqsave(&ag->lock, flags);
25
26         if (phydev->link) {
27                 if (ag->duplex != phydev->duplex
28                     || ag->speed != phydev->speed) {
29                         status_change = 1;
30                 }
31         }
32
33         if (phydev->link != ag->link)
34                 status_change = 1;
35
36         ag->link = phydev->link;
37         ag->duplex = phydev->duplex;
38         ag->speed = phydev->speed;
39
40         if (status_change)
41                 ag71xx_link_adjust(ag);
42
43         spin_unlock_irqrestore(&ag->lock, flags);
44 }
45
46 int ag71xx_phy_connect(struct ag71xx *ag)
47 {
48         struct device_node *np = ag->pdev->dev.of_node;
49         struct device_node *phy_node;
50         int ret;
51
52         if (of_phy_is_fixed_link(np)) {
53                 ret = of_phy_register_fixed_link(np);
54                 if (ret < 0) {
55                         dev_err(&ag->pdev->dev,
56                                 "Failed to register fixed PHY link: %d\n", ret);
57                         return ret;
58                 }
59
60                 phy_node = of_node_get(np);
61         } else {
62                 phy_node = of_parse_phandle(np, "phy-handle", 0);
63         }
64
65         if (!phy_node) {
66                 dev_err(&ag->pdev->dev,
67                         "Could not find valid phy node\n");
68                 return -ENODEV;
69         }
70
71         ag->phy_dev = of_phy_connect(ag->dev, phy_node, ag71xx_phy_link_adjust,
72                                      0, ag->phy_if_mode);
73
74         of_node_put(phy_node);
75
76         if (!ag->phy_dev) {
77                 dev_err(&ag->pdev->dev,
78                         "Could not connect to PHY device. Deferring probe.\n");
79                 return -EPROBE_DEFER;
80         }
81
82         dev_info(&ag->pdev->dev, "connected to PHY at %s [uid=%08x, driver=%s]\n",
83                     phydev_name(ag->phy_dev),
84                     ag->phy_dev->phy_id, ag->phy_dev->drv->name);
85
86         return 0;
87 }
88
89 void ag71xx_phy_disconnect(struct ag71xx *ag)
90 {
91         phy_disconnect(ag->phy_dev);
92 }