58db559ecf3d81a56a55c853c1f548df208264d8
2 * Atheros AR71xx built-in ethernet mac driver
4 * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
7 * Based on Atheros' AG7100 driver
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.
16 static void ag71xx_phy_link_adjust(struct net_device
*dev
)
18 struct ag71xx
*ag
= netdev_priv(dev
);
19 struct phy_device
*phydev
= ag
->phy_dev
;
21 int status_change
= 0;
23 spin_lock_irqsave(&ag
->lock
, flags
);
26 if (ag
->duplex
!= phydev
->duplex
27 || ag
->speed
!= phydev
->speed
) {
32 if (phydev
->link
!= ag
->link
)
35 ag
->link
= phydev
->link
;
36 ag
->duplex
= phydev
->duplex
;
37 ag
->speed
= phydev
->speed
;
40 ag71xx_link_adjust(ag
);
42 spin_unlock_irqrestore(&ag
->lock
, flags
);
45 void ag71xx_phy_start(struct ag71xx
*ag
)
47 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
50 phy_start(ag
->phy_dev
);
51 } else if (pdata
->mii_bus_dev
&& pdata
->switch_data
) {
52 ag71xx_ar7240_start(ag
);
55 ag71xx_link_adjust(ag
);
59 void ag71xx_phy_stop(struct ag71xx
*ag
)
61 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
65 phy_stop(ag
->phy_dev
);
66 else if (pdata
->mii_bus_dev
&& pdata
->switch_data
)
67 ag71xx_ar7240_stop(ag
);
69 spin_lock_irqsave(&ag
->lock
, flags
);
72 ag71xx_link_adjust(ag
);
74 spin_unlock_irqrestore(&ag
->lock
, flags
);
77 static int ag71xx_phy_connect_fixed(struct ag71xx
*ag
)
79 struct platform_device
*pdev
= ag
->pdev
;
80 struct device
*dev
= NULL
;
81 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
93 pr_err("Missing PHY for %s", dev_name(dev
));
97 /* use fixed settings */
98 switch (pdata
->speed
) {
104 dev_err(dev
, "invalid speed specified\n");
109 dev_dbg(dev
, "using fixed link parameters\n");
111 ag
->duplex
= pdata
->duplex
;
112 ag
->speed
= pdata
->speed
;
115 dev_info(dev
, "connected to fixed PHY at %s [uid=%08x, driver=%s]\n",
116 phydev_name(ag
->phy_dev
),
117 ag
->phy_dev
->phy_id
, ag
->phy_dev
->drv
->name
);
119 pr_err("Failed to connect to fixed PHY\n");
124 static int ag71xx_phy_connect_multi(struct ag71xx
*ag
)
126 struct device
*dev
= &ag
->pdev
->dev
;
127 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
128 struct phy_device
*phydev
= NULL
;
132 for (phy_addr
= 0; phy_addr
< PHY_MAX_ADDR
; phy_addr
++) {
133 if (!(pdata
->phy_mask
& (1 << phy_addr
)))
136 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
137 if (ag
->mii_bus
->phy_map
[phy_addr
] == NULL
)
140 DBG("%s: PHY found at %s, uid=%08x\n",
142 dev_name(&ag
->mii_bus
->phy_map
[phy_addr
]->dev
),
143 &ag
->mii_bus
->phy_map
[phy_addr
]->phy_id
),
144 &ag
->mii_bus
->phy_map
[phy_addr
]->phy_id
: 0);
147 phydev
= ag
->mii_bus
->phy_map
[phy_addr
];
149 if (ag
->mii_bus
->mdio_map
[phy_addr
] == NULL
)
152 DBG("%s: PHY found at %s, uid=%08x\n",
154 dev_name(&ag
->mii_bus
->mdio_map
[phy_addr
]->dev
),
155 mdiobus_get_phy(ag
->mii_bus
, phy_addr
) ?
156 mdiobus_get_phy(ag
->mii_bus
, phy_addr
)->phy_id
: 0);
159 phydev
= mdiobus_get_phy(ag
->mii_bus
, phy_addr
);
164 dev_err(dev
, "no PHY found with phy_mask=%08x\n",
169 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
170 ag
->phy_dev
= phy_connect(ag
->dev
, dev_name(&phydev
->dev
),
172 ag
->phy_dev
= phy_connect(ag
->dev
, phydev_name(phydev
),
174 &ag71xx_phy_link_adjust
,
177 if (IS_ERR(ag
->phy_dev
)) {
178 dev_err(dev
, "could not connect to PHY at %s\n",
179 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
180 dev_name(&phydev
->dev
));
182 phydev_name(phydev
));
184 return PTR_ERR(ag
->phy_dev
);
187 /* mask with MAC supported features */
189 phydev
->supported
&= PHY_GBIT_FEATURES
;
191 phydev
->supported
&= PHY_BASIC_FEATURES
;
193 phydev
->advertising
= phydev
->supported
;
195 dev_info(dev
, "connected to PHY at %s [uid=%08x, driver=%s]\n",
196 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0)
197 dev_name(&phydev
->dev
),
201 phydev
->phy_id
, phydev
->drv
->name
);
210 static int dev_is_class(struct device
*dev
, void *class)
212 if (dev
->class != NULL
&& !strcmp(dev
->class->name
, class))
218 static struct device
*dev_find_class(struct device
*parent
, char *class)
220 if (dev_is_class(parent
, class)) {
225 return device_find_child(parent
, class, dev_is_class
);
228 static struct mii_bus
*dev_to_mii_bus(struct device
*dev
)
232 d
= dev_find_class(dev
, "mdio_bus");
245 int ag71xx_phy_connect(struct ag71xx
*ag
)
247 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
249 if (pdata
->mii_bus_dev
== NULL
||
250 pdata
->mii_bus_dev
->bus
== NULL
)
251 return ag71xx_phy_connect_fixed(ag
);
253 ag
->mii_bus
= dev_to_mii_bus(pdata
->mii_bus_dev
);
254 if (ag
->mii_bus
== NULL
) {
255 dev_err(&ag
->pdev
->dev
, "unable to find MII bus on device '%s'\n",
256 dev_name(pdata
->mii_bus_dev
));
260 /* Reset the mdio bus explicitly */
261 if (ag
->mii_bus
->reset
) {
262 mutex_lock(&ag
->mii_bus
->mdio_lock
);
263 ag
->mii_bus
->reset(ag
->mii_bus
);
264 mutex_unlock(&ag
->mii_bus
->mdio_lock
);
267 if (pdata
->switch_data
)
268 return ag71xx_ar7240_init(ag
);
271 return ag71xx_phy_connect_multi(ag
);
273 return ag71xx_phy_connect_fixed(ag
);
276 void ag71xx_phy_disconnect(struct ag71xx
*ag
)
278 struct ag71xx_platform_data
*pdata
= ag71xx_get_pdata(ag
);
280 if (pdata
->switch_data
)
281 ag71xx_ar7240_cleanup(ag
);
282 else if (ag
->phy_dev
)
283 phy_disconnect(ag
->phy_dev
);