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,                               &reg_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 来配对的.


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑光标不动了怎么办 苹果六按键失灵怎么办 iphone屏幕碎了怎么办 oppo手机内屏坏了怎么办 手机充电变慢怎么办 手机内屏分离怎么办 电脑屏幕摔碎了怎么办 三星手机外屏碎了怎么办 苹果手机外屏碎了怎么办 iphone6s听筒坏了怎么办 苹果x外屏碎了怎么办 苹果手机屏摔坏了怎么办 苹果8外屏摔碎了怎么办 苹果7内屏坏了怎么办 苹果手机屏幕里面有水痕怎么办 iphone6屏幕摔裂怎么办 苹果手机电池坏了怎么办 苹果手机充电器坏了怎么办 苹果充电器老是坏怎么办 苹果手机屏幕失控了怎么办 手机自己乱点怎么办 手机点屏幕没用怎么办 手机界面不动了怎么办 手机关不了机怎么办 小米5花屏怎么办 小米手机死机怎么办呢 手机触屏失灵怎么办? 手机触屏不行怎么办 苹果手机屏幕触摸失灵怎么办 苹果7按键失灵怎么办 苹果中间键失灵怎么办 苹果屏触摸不灵怎么办 ipad屏幕乱跳怎么办 屏幕自己乱点怎么办 手机触屏漂移怎么办 玩不好飘频怎么办 苹果手机城乱码了怎么办 苹果手机屏幕乱跳怎么办 苹果笔记本键盘乱码怎么办 苹果电脑打开word乱码怎么办 iphone5s屏幕竖纹怎么办