static int davinci_mdio_probe(struct platform_device *pdev) { struct mdio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct davinci_mdio_data *data; struct resource *res; struct phy_device *phy; int ret, addr; int autosuspend_delay_ms = -1; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->manual_mode = false; data->bb_ctrl.ops = &davinci_mdiobb_ops; if (IS_ENABLED(CONFIG_OF) && dev->of_node) { const struct soc_device_attribute *soc_match_data; soc_match_data = soc_device_match(k3_mdio_socinfo); if (soc_match_data && soc_match_data->data) { const struct k3_mdio_soc_data *socdata = soc_match_data->data; data->manual_mode = socdata->manual_mode; } } if (data->manual_mode) data->bus = alloc_mdio_bitbang(&data->bb_ctrl); else data->bus = devm_mdiobus_alloc(dev); if (!data->bus) { dev_err(dev, "failed to alloc mii bus\n"); return -ENOMEM; } if (IS_ENABLED(CONFIG_OF) && dev->of_node) { const struct davinci_mdio_of_param *of_mdio_data; ret = davinci_mdio_probe_dt(&data->pdata, pdev); if (ret) return ret; snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); of_mdio_data = of_device_get_match_data(&pdev->dev); if (of_mdio_data) { autosuspend_delay_ms = of_mdio_data->autosuspend_delay_ms; } } else { data->pdata = pdata ? (*pdata) : default_pdata; snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id); } data->bus->name = dev_name(dev); if (data->manual_mode) { data->bus->read = davinci_mdiobb_read_c22; data->bus->write = davinci_mdiobb_write_c22; data->bus->read_c45 = davinci_mdiobb_read_c45; data->bus->write_c45 = davinci_mdiobb_write_c45; data->bus->reset = davinci_mdiobb_reset; dev_info(dev, "Configuring MDIO in manual mode\n"); } else { data->bus->read = davinci_mdio_read; data->bus->write = davinci_mdio_write; data->bus->reset = davinci_mdio_reset; data->bus->priv = data; } data->bus->parent = dev; data->clk = devm_clk_get(dev, "fck"); if (IS_ERR(data->clk)) { dev_err(dev, "failed to get device clock\n"); return PTR_ERR(data->clk); } dev_set_drvdata(dev, data); data->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EINVAL; data->regs = devm_ioremap(dev, res->start, resource_size(res)); if (!data->regs) return -ENOMEM; davinci_mdio_init_clk(data); pm_runtime_set_autosuspend_delay(&pdev->dev, autosuspend_delay_ms); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); /* register the mii bus * Create PHYs from DT only in case if PHY child nodes are explicitly * defined to support backward compatibility with DTs which assume that * Davinci MDIO will always scan the bus for PHYs detection. */ if (dev->of_node && of_get_child_count(dev->of_node)) data->skip_scan = true; ret = of_mdiobus_register(data->bus, dev->of_node); if (ret) goto bail_out; // »ñÈ¡PHY¸´Î»GPIO rmii1_reset_gpio = devm_gpiod_get_optional(dev, "rmii1-reset", GPIOD_OUT_LOW); if (IS_ERR(rmii1_reset_gpio)) { ret = PTR_ERR(rmii1_reset_gpio); goto bail_out; } rmii2_reset_gpio = devm_gpiod_get_optional(dev, "rmii2-reset", GPIOD_OUT_LOW); if (IS_ERR(rmii2_reset_gpio)) { ret = PTR_ERR(rmii2_reset_gpio); goto bail_out; } if (rmii1_reset_gpio && rmii2_reset_gpio) { gpiod_set_value_cansleep(rmii1_reset_gpio, 1); gpiod_set_value_cansleep(rmii2_reset_gpio, 0); msleep(500); } /* Configure the 8512 PHY chip and disable the broadcast address. */ int phy_addr = 1; u16 original_val, modified_val; ret = data->bus->write(data->bus, phy_addr, 0x1e, 0x0000); if (ret) { dev_err(dev, "Failed to write to PHY 0x1e register\n"); goto bail_out; } original_val = data->bus->read(data->bus, phy_addr, 0x1f); dev_info(dev, "PHY %d register (0x1f) original value: 0x%04x\n", phy_addr, original_val); modified_val = original_val & ~(0x3 << 5); // clear bit5 bit6 ret = data->bus->write(data->bus, phy_addr, 0x1f, modified_val); if (ret) { dev_err(dev, "Failed to write modified value to PHY 0x1f register\n"); goto bail_out; } dev_info(dev, "PHY %d broadcast address disabled: bit5-6 cleared, new value: 0x%04x\n", phy_addr, modified_val); if (rmii2_reset_gpio) { gpiod_set_value_cansleep(rmii2_reset_gpio, 1); msleep(500); } /* config test */ int switch_addr = 0; ret = data->bus->write(data->bus, switch_addr, 0x1f, 0x003c); if (ret) { dev_err(dev, "Failed to configure switch\n"); goto bail_out; } u16 switch_reg = data->bus->read(data->bus, switch_addr, 0x1f); dev_info(dev, "PHY %d register (0x1f) original value: 0x%04x\n", switch_addr, switch_reg); switch_reg = data->bus->read(data->bus, switch_addr, 0x00); dev_info(dev, "PHY %d register (0x00) original value: 0x%04x\n", switch_addr, switch_reg); switch_reg = data->bus->read(data->bus, switch_addr, 0x0e); dev_info(dev, "PHY %d register (0x0e) original value: 0x%04x\n", switch_addr, switch_reg); /* scan and dump the bus */ for (addr = 0; addr < PHY_MAX_ADDR; addr++) { phy = mdiobus_get_phy(data->bus, addr); if (phy) { dev_info(dev, "phy[%d]: device %s, driver %s\n", phy->mdio.addr, phydev_name(phy), phy->drv ? phy->drv->name : "unknown"); } } return 0; bail_out: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; }