procd: update to latest git HEAD
[openwrt/openwrt.git] / target / linux / ath79 / files-4.19 / 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 }