phy device 和 driver
来源:互联网 发布:xy苹果助手下载mac版 编辑:程序博客网 时间:2024/06/05 19:50
phy的驱动分为platform_driver_register和platform_device_register 两部分。这两部分都是挂在mdio总线上。这里以hns驱动为例。说先定义mido对应的struct mii_bus *new_bus;static int hns_mdio_probe(struct platform_device *pdev){ struct hns_mdio_device *mdio_dev; struct mii_bus *new_bus; struct resource *res; int ret = -ENODEV; if (!pdev) { dev_err(NULL, "pdev is NULL!\r\n"); return -ENODEV; } mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL); if (!mdio_dev) return -ENOMEM; new_bus = devm_mdiobus_alloc(&pdev->dev); if (!new_bus) { dev_err(&pdev->dev, "mdiobus_alloc fail!\n"); return -ENOMEM; } new_bus->name = MDIO_BUS_NAME; new_bus->read = hns_mdio_read; new_bus->write = hns_mdio_write; new_bus->reset = hns_mdio_reset; new_bus->priv = mdio_dev; new_bus->parent = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdio_dev->vbase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(mdio_dev->vbase)) { ret = PTR_ERR(mdio_dev->vbase); return ret; } platform_set_drvdata(pdev, new_bus); snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%s", "Mii", dev_name(&pdev->dev)); if (dev_of_node(&pdev->dev)) { struct of_phandle_args reg_args; ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, "subctrl-vbase", 4, 0, ®_args); if (!ret) { mdio_dev->subctrl_vbase = syscon_node_to_regmap(reg_args.np); if (IS_ERR(mdio_dev->subctrl_vbase)) { dev_warn(&pdev->dev, "syscon_node_to_regmap error\n"); mdio_dev->subctrl_vbase = NULL; } else { if (reg_args.args_count == 4) { mdio_dev->sc_reg.mdio_clk_en = (u16)reg_args.args[0]; mdio_dev->sc_reg.mdio_clk_dis = (u16)reg_args.args[0] + 4; mdio_dev->sc_reg.mdio_reset_req = (u16)reg_args.args[1]; mdio_dev->sc_reg.mdio_reset_dreq = (u16)reg_args.args[1] + 4; mdio_dev->sc_reg.mdio_clk_st = (u16)reg_args.args[2]; mdio_dev->sc_reg.mdio_reset_st = (u16)reg_args.args[3]; } else { /* for compatible */ mdio_dev->sc_reg.mdio_clk_en = MDIO_SC_CLK_EN; mdio_dev->sc_reg.mdio_clk_dis = MDIO_SC_CLK_DIS; mdio_dev->sc_reg.mdio_reset_req = MDIO_SC_RESET_REQ; mdio_dev->sc_reg.mdio_reset_dreq = MDIO_SC_RESET_DREQ; mdio_dev->sc_reg.mdio_clk_st = MDIO_SC_CLK_ST; mdio_dev->sc_reg.mdio_reset_st = MDIO_SC_RESET_ST; } } } else { dev_warn(&pdev->dev, "find syscon ret = %#x\n", ret); mdio_dev->subctrl_vbase = NULL; } ret = of_mdiobus_register(new_bus, pdev->dev.of_node); } else if (is_acpi_node(pdev->dev.fwnode)) { /* Clear all the IRQ properties */ memset(new_bus->irq, PHY_POLL, 4 * PHY_MAX_ADDR); /* Mask out all PHYs from auto probing. */ new_bus->phy_mask = ~0; /* Register the MDIO bus */核心是调用mdiobus_register,然后scan这个bus上对应的device ret = mdiobus_register(new_bus); } else { dev_err(&pdev->dev, "Can not get cfg data from DT or ACPI\n"); ret = -ENXIO; } if (ret) { dev_err(&pdev->dev, "Cannot register as MDIO bus!\n"); platform_set_drvdata(pdev, NULL); return ret; } return 0;}mdiobus_register->__mdiobus_register for (i = 0; i < PHY_MAX_ADDR; i++) { if ((bus->phy_mask & (1 << i)) == 0) { struct phy_device *phydev; phydev = mdiobus_scan(bus, i); if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) { err = PTR_ERR(phydev); goto error; } } }根据phy id去通过上面注册的mdio的read函数实际去读芯片的寄存器,看这个phy id 对应的device是否存在struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr){ struct phy_device *phydev; int err; phydev = get_phy_device(bus, addr, false); if (IS_ERR(phydev)) return phydev; /* * For DT, see if the auto-probed phy has a correspoding child * in the bus node, and set the of_node pointer in this case. */ of_mdiobus_link_mdiodev(bus, &phydev->mdio); err = phy_device_register(phydev); if (err) { phy_device_free(phydev); return ERR_PTR(-ENODEV); } return phydev;}如果get_phy_device 返回成功的话,说明这个phy id对应的硬件是存在的,就调用phy_device_register 创建phy devicestatic int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids){ int phy_reg; if (is_c45) return get_phy_c45_ids(bus, addr, phy_id, c45_ids); /* Grab the bits from PHYIR1, and put them in the upper half */ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); if (phy_reg < 0) return -EIO; *phy_id = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); if (phy_reg < 0) return -EIO; *phy_id |= (phy_reg & 0xffff); return 0;}可见最终通过mdiobus_read 去读寄存器int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum){ int retval; BUG_ON(in_interrupt()); mutex_lock(&bus->mdio_lock); retval = bus->read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); trace_mdio_access(bus, 1, addr, regnum, retval, retval); return retval;}最终调用mido bus的read函数去读的。到这里已经准备好phy device。下来就要调用module_phy_driver(marvell_drivers); 来注册phy driver那phy的device和driver是如何配对的呢?get_phy_device->phy_device_createstruct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids){ struct phy_device *dev; struct mdio_device *mdiodev; /* We allocate the device, and initialize the default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM); mdiodev = &dev->mdio; mdiodev->dev.release = phy_device_release; mdiodev->dev.parent = &bus->dev; mdiodev->dev.bus = &mdio_bus_type; mdiodev->bus = bus; mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS; mdiodev->bus_match = phy_bus_match;}可以看到bus_match 函数是phy_bus_matchstatic int phy_bus_match(struct device *dev, struct device_driver *drv){ struct phy_device *phydev = to_phy_device(dev); struct phy_driver *phydrv = to_phy_driver(drv); const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); int i; if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) return 0; if (phydrv->match_phy_device) return phydrv->match_phy_device(phydev); if (phydev->is_c45) { for (i = 1; i < num_ids; i++) { if (!(phydev->c45_ids.devices_in_package & (1 << i))) continue; if ((phydrv->phy_id & phydrv->phy_id_mask) == (phydev->c45_ids.device_ids[i] & phydrv->phy_id_mask)) return 1; } return 0; } else { return (phydrv->phy_id & phydrv->phy_id_mask) == (phydev->phy_id & phydrv->phy_id_mask); }}从phy_bus_match 中可以知道是根据phy id 来配对的.
阅读全文
0 0
- phy device 和 driver
- bus,device和driver
- platform device和platform driver
- platform device和platform driver
- platform device和platform driver
- platform device和platform driver
- add new LAN8710 and LAN8720 device ids to smsc phy driver
- phy device的注册
- Device Driver
- platform device和driver之间的关系
- 《Linux device driver》字符设备和scull
- device_bind_driver 收到绑定device和driver
- platform平台device和driver如何匹配
- vf的device和driver的匹配
- phy device的添加流程
- phy device的添加流程 .
- Linux Device Driver: char device
- Linux Device和Driver注册过程,以及Probe的时机
- 概率论(二)- 随机事件与随机事件的概率
- jQuery尺寸相关、滚动事件
- js:发布订阅模式
- StringBuffer、StringBuilder
- 【数据库学习】MongoDB环境搭建配置及可视化工具使用(win10)
- phy device 和 driver
- 破解学生端
- python 正则表达式
- css3(3)
- AngularJs:Controller数据共享、继承、通信使用详解
- 子类覆盖父类的方法
- 米斯特白帽子WEB安全攻防培训-信息收集
- 多目标跟踪计数opencv(C++实现)
- 一天一道leetcode