// SPDX-License-Identifier: GPL-2.0-or-later /* * ASIX AX88172A based USB 2.0 Ethernet Devices * Copyright (C) 2012 OMICRON electronics GmbH * * Supports external PHYs via phylib. Based on the driver for the * AX88772. Original copyrights follow: * * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> * Copyright (C) 2006 James Painter <jamie.painter@iname.com> * Copyright (c) 2002-2003 TiVo Inc.
*/
/* set MAC link settings according to information from phylib */ staticvoid ax88172a_adjust_link(struct net_device *netdev)
{ struct phy_device *phydev = netdev->phydev; struct usbnet *dev = netdev_priv(netdev); struct ax88172a_private *priv = dev->driver_priv;
u16 mode = 0;
if (phydev->link) {
mode = AX88772_MEDIUM_DEFAULT;
if (phydev->duplex == DUPLEX_HALF)
mode &= ~AX_MEDIUM_FD;
if (phydev->speed != SPEED_100)
mode &= ~AX_MEDIUM_PS;
}
ret = usbnet_get_endpoints(dev, intf); if (ret) return ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
dev->driver_priv = priv;
/* Get the MAC address */
ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0); if (ret < ETH_ALEN) {
netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
ret = -EIO; goto free;
}
eth_hw_addr_set(dev->net, buf);
/* are we using the internal or the external phy? */
ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf, 0); if (ret < 0) {
netdev_err(dev->net, "Failed to read software interface selection register: %d\n",
ret); goto free;
}
netdev_dbg(dev->net, "AX_CMD_SW_PHY_STATUS = 0x%02x\n", buf[0]); switch (buf[0] & AX_PHY_SELECT_MASK) { case AX_PHY_SELECT_INTERNAL:
netdev_dbg(dev->net, "use internal phy\n");
priv->use_embdphy = 1; break; case AX_PHY_SELECT_EXTERNAL:
netdev_dbg(dev->net, "use external phy\n");
priv->use_embdphy = 0; break; default:
netdev_err(dev->net, "Interface mode not supported by driver\n");
ret = -ENOTSUPP; goto free;
}
ret = asix_read_phy_addr(dev, priv->use_embdphy); if (ret < 0) goto free; if (ret >= PHY_MAX_ADDR) {
netdev_err(dev->net, "Invalid PHY address %#x\n", ret);
ret = -ENODEV; goto free;
}
priv->phy_addr = ret;
ax88172a_reset_phy(dev, priv->use_embdphy);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ if (dev->driver_info->flags & FLAG_FRAMING_AX) { /* hard_mtu is still the default - the device does not support
jumbo eth frames */
dev->rx_urb_size = 2048;
}
/* init MDIO bus */
ret = ax88172a_init_mdio(dev); if (ret) goto free;
/* Rewrite MAC address */
memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
data->mac_addr, 0); if (ret < 0) goto out;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0); if (ret < 0) goto out;
rx_ctl = asix_read_rx_ctl(dev, 0);
netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
rx_ctl);
rx_ctl = asix_read_medium_status(dev, 0);
netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n",
rx_ctl);
/* Connect to PHY */
snprintf(priv->phy_name, sizeof(priv->phy_name), PHY_ID_FMT,
priv->mdio->id, priv->phy_addr);
priv->phydev = phy_connect(dev->net, priv->phy_name,
&ax88172a_adjust_link,
PHY_INTERFACE_MODE_MII); if (IS_ERR(priv->phydev)) {
netdev_err(dev->net, "Could not connect to PHY device %s\n",
priv->phy_name);
ret = PTR_ERR(priv->phydev); goto out;
}
netdev_info(dev->net, "Connected to phy %s\n", priv->phy_name);
/* During power-up, the AX88172A set the power down (BMCR_PDOWN) * bit of the PHY. Bring the PHY up again.
*/
genphy_resume(priv->phydev);
phy_start(priv->phydev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.