static int bcm_sf2_mdio_register(struct dsa_switch *ds) { struct bcm_sf2_priv *priv = ds_to_priv(ds); struct device_node *dn; static int index; int err; /* Find our integrated MDIO bus node */ dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio"); priv->master_mii_bus = of_mdio_find_bus(dn); if (!priv->master_mii_bus) return -EPROBE_DEFER; get_device(&priv->master_mii_bus->dev); priv->master_mii_dn = dn; priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev); if (!priv->slave_mii_bus) return -ENOMEM; priv->slave_mii_bus->priv = priv; priv->slave_mii_bus->name = "sf2 slave mii"; priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read; priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write; snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d", index++); priv->slave_mii_bus->dev.of_node = dn; /* Include the pseudo-PHY address to divert reads towards our * workaround. This is only required for 7445D0, since 7445E0 * disconnects the internal switch pseudo-PHY such that we can use the * regular SWITCH_MDIO master controller instead. * * Here we flag the pseudo PHY as needing special treatment and would * otherwise make all other PHY read/writes go to the master MDIO bus * controller that comes with this switch backed by the "mdio-unimac" * driver. */ if (of_machine_is_compatible("brcm,bcm7445d0")) priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR); else priv->indir_phy_mask = 0; ds->phys_mii_mask = priv->indir_phy_mask; ds->slave_mii_bus = priv->slave_mii_bus; priv->slave_mii_bus->parent = ds->dev->parent; priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask; if (dn) err = of_mdiobus_register(priv->slave_mii_bus, dn); else err = mdiobus_register(priv->slave_mii_bus); if (err) of_node_put(dn); return err; }
static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np) { struct dsa_switch *ds = priv->ds; ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev); if (!ds->slave_mii_bus) return -ENOMEM; ds->slave_mii_bus->priv = priv; ds->slave_mii_bus->read = gswip_mdio_rd; ds->slave_mii_bus->write = gswip_mdio_wr; ds->slave_mii_bus->name = "lantiq,xrx200-mdio"; snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(priv->dev)); ds->slave_mii_bus->parent = priv->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; return of_mdiobus_register(ds->slave_mii_bus, mdio_np); }
static int mdio_mux_iproc_probe(struct platform_device *pdev) { struct iproc_mdiomux_desc *md; struct mii_bus *bus; struct resource *res; int rc; md = devm_kzalloc(&pdev->dev, sizeof(*md), GFP_KERNEL); if (!md) return -ENOMEM; md->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res->start & 0xfff) { /* For backward compatibility in case the * base address is specified with an offset. */ dev_info(&pdev->dev, "fix base address in dt-blob\n"); res->start &= ~0xfff; res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1; } md->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(md->base)) { dev_err(&pdev->dev, "failed to ioremap register\n"); return PTR_ERR(md->base); } md->mii_bus = devm_mdiobus_alloc(&pdev->dev); if (!md->mii_bus) { dev_err(&pdev->dev, "mdiomux bus alloc failed\n"); return -ENOMEM; } md->core_clk = devm_clk_get(&pdev->dev, NULL); if (md->core_clk == ERR_PTR(-ENOENT) || md->core_clk == ERR_PTR(-EINVAL)) md->core_clk = NULL; else if (IS_ERR(md->core_clk)) return PTR_ERR(md->core_clk); rc = clk_prepare_enable(md->core_clk); if (rc) { dev_err(&pdev->dev, "failed to enable core clk\n"); return rc; } bus = md->mii_bus; bus->priv = md; bus->name = "iProc MDIO mux bus"; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); bus->parent = &pdev->dev; bus->read = iproc_mdiomux_read; bus->write = iproc_mdiomux_write; bus->phy_mask = ~0; bus->dev.of_node = pdev->dev.of_node; rc = mdiobus_register(bus); if (rc) { dev_err(&pdev->dev, "mdiomux registration failed\n"); goto out_clk; } platform_set_drvdata(pdev, md); rc = mdio_mux_init(md->dev, md->dev->of_node, mdio_mux_iproc_switch_fn, &md->mux_handle, md, md->mii_bus); if (rc) { dev_info(md->dev, "mdiomux initialization failed\n"); goto out_register; } mdio_mux_iproc_config(md); dev_info(md->dev, "iProc mdiomux registered\n"); return 0; out_register: mdiobus_unregister(bus); out_clk: clk_disable_unprepare(md->core_clk); return rc; }
/* Configure the MDIO bus and connect the external PHY */ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) { struct device_node *np = pdev->dev.of_node; struct mii_bus *mii_bus; int ret; /* Create the mii_bus object for talking to the MDIO bus */ adpt->mii_bus = mii_bus = devm_mdiobus_alloc(&pdev->dev); if (!mii_bus) return -ENOMEM; mii_bus->name = "emac-mdio"; snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); mii_bus->read = emac_mdio_read; mii_bus->write = emac_mdio_write; mii_bus->parent = &pdev->dev; mii_bus->priv = adpt; if (has_acpi_companion(&pdev->dev)) { u32 phy_addr; ret = mdiobus_register(mii_bus); if (ret) { dev_err(&pdev->dev, "could not register mdio bus\n"); return ret; } ret = device_property_read_u32(&pdev->dev, "phy-channel", &phy_addr); if (ret) /* If we can't read a valid phy address, then assume * that there is only one phy on this mdio bus. */ adpt->phydev = phy_find_first(mii_bus); else adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr); /* of_phy_find_device() claims a reference to the phydev, * so we do that here manually as well. When the driver * later unloads, it can unilaterally drop the reference * without worrying about ACPI vs DT. */ if (adpt->phydev) get_device(&adpt->phydev->mdio.dev); } else { struct device_node *phy_np; ret = of_mdiobus_register(mii_bus, np); if (ret) { dev_err(&pdev->dev, "could not register mdio bus\n"); return ret; } phy_np = of_parse_phandle(np, "phy-handle", 0); adpt->phydev = of_phy_find_device(phy_np); of_node_put(phy_np); } if (!adpt->phydev) { dev_err(&pdev->dev, "could not find external phy\n"); mdiobus_unregister(mii_bus); return -ENODEV; } return 0; }
static int dsa_ds_apply(struct dsa_switch_tree *dst, struct dsa_switch *ds) { struct dsa_port *port; u32 index; int err; /* Initialize ds->phys_mii_mask before registering the slave MDIO bus * driver and before ops->setup() has run, since the switch drivers and * the slave MDIO bus driver rely on these values for probing PHY * devices or not */ ds->phys_mii_mask = ds->enabled_port_mask; /* Add the switch to devlink before calling setup, so that setup can * add dpipe tables */ ds->devlink = devlink_alloc(&dsa_devlink_ops, 0); if (!ds->devlink) return -ENOMEM; err = devlink_register(ds->devlink, ds->dev); if (err) return err; err = ds->ops->setup(ds); if (err < 0) return err; err = dsa_switch_register_notifier(ds); if (err) return err; if (ds->ops->set_addr) { err = ds->ops->set_addr(ds, dst->cpu_dp->netdev->dev_addr); if (err < 0) return err; } if (!ds->slave_mii_bus && ds->ops->phy_read) { ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); if (!ds->slave_mii_bus) return -ENOMEM; dsa_slave_mii_bus_init(ds); err = mdiobus_register(ds->slave_mii_bus); if (err < 0) return err; } for (index = 0; index < ds->num_ports; index++) { port = &ds->ports[index]; if (!dsa_port_is_valid(port)) continue; if (dsa_port_is_dsa(port)) { err = dsa_dsa_port_apply(port); if (err) return err; continue; } if (dsa_port_is_cpu(port)) { err = dsa_cpu_port_apply(port); if (err) return err; continue; } err = dsa_user_port_apply(port); if (err) continue; } return 0; }