static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; struct bcmgenet_platform_data *pd = kdev->platform_data; struct mii_bus *mdio = priv->mii_bus; struct phy_device *phydev; int ret; if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) { /* * Internal or external PHY with MDIO access */ if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR) mdio->phy_mask = ~(1 << pd->phy_address); else mdio->phy_mask = 0; ret = mdiobus_register(mdio); if (ret) { dev_err(kdev, "failed to register MDIO bus\n"); return ret; } if (pd->phy_address >= 0 && pd->phy_address < PHY_MAX_ADDR) phydev = mdio->phy_map[pd->phy_address]; else phydev = phy_find_first(mdio); if (!phydev) { dev_err(kdev, "failed to register PHY device\n"); mdiobus_unregister(mdio); return -ENODEV; } } else { /* * MoCA port or no MDIO access. * Use fixed PHY to represent the link layer. */ struct fixed_phy_status fphy_status = { .link = 1, .speed = pd->phy_speed, .duplex = pd->phy_duplex, .pause = 0, .asym_pause = 0, }; phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); if (!phydev || IS_ERR(phydev)) { dev_err(kdev, "failed to register fixed PHY device\n"); return -ENODEV; } } priv->phydev = phydev; priv->phy_interface = pd->phy_interface; return 0; } static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; if (dn) return bcmgenet_mii_of_init(priv); else return bcmgenet_mii_pd_init(priv); } int bcmgenet_mii_init(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); int ret; ret = bcmgenet_mii_alloc(priv); if (ret) return ret; ret = bcmgenet_mii_bus_init(priv); if (ret) goto out_free; ret = bcmgenet_mii_probe(dev); if (ret) goto out; return 0; out: of_node_put(priv->phy_dn); mdiobus_unregister(priv->mii_bus); out_free: kfree(priv->mii_bus->irq); mdiobus_free(priv->mii_bus); return ret; } void bcmgenet_mii_exit(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); of_node_put(priv->phy_dn); mdiobus_unregister(priv->mii_bus); kfree(priv->mii_bus->irq); mdiobus_free(priv->mii_bus); }
static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; struct bcmgenet_platform_data *pd = kdev->platform_data; char phy_name[MII_BUS_ID_SIZE + 3]; char mdio_bus_id[MII_BUS_ID_SIZE]; struct phy_device *phydev; snprintf(mdio_bus_id, MII_BUS_ID_SIZE, "%s-%d", UNIMAC_MDIO_DRV_NAME, priv->pdev->id); if (pd->phy_interface != PHY_INTERFACE_MODE_MOCA && pd->mdio_enabled) { snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, pd->phy_address); /* * Internal or external PHY with MDIO access */ phydev = phy_attach(priv->dev, phy_name, pd->phy_interface); if (!phydev) { dev_err(kdev, "failed to register PHY device\n"); return -ENODEV; } } else { /* * MoCA port or no MDIO access. * Use fixed PHY to represent the link layer. */ struct fixed_phy_status fphy_status = { .link = 1, .speed = pd->phy_speed, .duplex = pd->phy_duplex, .pause = 0, .asym_pause = 0, }; phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); if (!phydev || IS_ERR(phydev)) { dev_err(kdev, "failed to register fixed PHY device\n"); return -ENODEV; } /* Make sure we initialize MoCA PHYs with a link down */ phydev->link = 0; } priv->phy_interface = pd->phy_interface; return 0; } static int bcmgenet_mii_bus_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; if (dn) return bcmgenet_mii_of_init(priv); else return bcmgenet_mii_pd_init(priv); } int bcmgenet_mii_init(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); int ret; ret = bcmgenet_mii_register(priv); if (ret) return ret; ret = bcmgenet_mii_bus_init(priv); if (ret) goto out; return 0; out: bcmgenet_mii_exit(dev); return ret; } void bcmgenet_mii_exit(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device_node *dn = priv->pdev->dev.of_node; if (of_phy_is_fixed_link(dn)) of_phy_deregister_fixed_link(dn); of_node_put(priv->phy_dn); platform_device_unregister(priv->mii_pdev); }