PHY 子系统框架介绍
PHY 子系统是 Linux 内核中的一个子系统,它的全称是物理层子系统(Physical Layer Subsystem),主要负责硬件物理层的驱动和管理,是 Linux 内核中与硬件物理层通信的接口。 PHY 子系统包含了许多控制器和 PHY 驱动,这些驱动用于管理系统中的不同 PHY 设备。
在 Linux 内核中,PHY 设备通常被描述为一个两部分的设备:一个是控制器(Controller),另一个是 PHY 设备本身。控制器驱动负责管理 PHY 设备,并在必要时与 PHY 设备通信,以确保其正确运行。 PHY 设备驱动负责实现与 PHY 设备的通信协议。
Linux PHY 子系统的核心 API 包括以下函数:
phy_create() 和 phy_destroy():创建和销毁 PHY 设备对象。
phy_attach() 和 phy_detach():将 PHY 设备对象与控制器设备对象进行关联和解除关联。
phy_init() 和 phy_exit():初始化和退出 PHY 设备。
phy_start() 和 phy_stop():启动和停止 PHY 设备。
phy_connect_direct() 和 phy_disconnect():直接连接和断开连接 PHY 设备。
phy_read() 和 phy_write():读取和写入 PHY 寄存器。
phy_modify():修改 PHY 寄存器中的某些位。
这些 API 函数允许控制器驱动和 PHY 设备驱动进行通信和控制。通过这些 API 函数,Linux PHY 子系统提供了一个简单的和可扩展的方法来管理和驱动系统中的各种 PHY 设备。
PHY 子系统常用的接口函数包括:
phy_register_device() 和 phy_unregister_device():用于注册和注销 PHY 设备。
phy_connect() 和 phy_disconnect():用于连接和断开 PHY 设备与网络设备之间的关联关系。
phy_start() 和 phy_stop():用于启动和停止 PHY 设备。
phy_suspend() 和 phy_resume():用于挂起和恢复 PHY 设备。
phy_read() 和 phy_write():用于读取和写入 PHY 设备的寄存器值。
phy_set_mode() 和 phy_ethtool_sset():分别用于设置 PHY 设备的工作模式和 Ethtool 配置项。
phy_start_aneg() 和 phy_stop_aneg():分别用于启动和停止 PHY 设备的自协商功能。
phy_set_max_speed() 和 phy_set_max_pause():分别用于设置 PHY 设备的最大速度和最大暂停时间。
phy_mii_ioctl() 和 phy_mii_bus_read():分别用于处理 PHY 设备的 ioctl 命令和读取 MII 总线上的寄存器值。
phy_print_status() 和 phy_print_regs():分别用于打印 PHY 设备的状态和寄存器值。
以上这些接口函数,可以用于编写 Linux 内核中的 PHY 驱动程序。
驱动例子
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
static int my_phy_init(struct phy_device *phydev)
{
printk(KERN_INFO "my_phy: PHY device at address %d\n", phydev->addr);
return 0;
}
static int my_phy_suspend(struct phy_device *phydev)
{
printk(KERN_INFO "my_phy: PHY device suspended\n");
return 0;
}
static int my_phy_resume(struct phy_device *phydev)
{
printk(KERN_INFO "my_phy: PHY device resumed\n");
return 0;
}
static struct phy_driver my_phy_driver = {
.name = "my_phy_driver",
.phy_id = { 0x00000000, 0x00000000 },
.features = PHY_BASIC_FEATURES,
.config_init = my_phy_init,
.suspend = my_phy_suspend,
.resume = my_phy_resume,
};
static int my_phy_probe(struct platform_device *pdev)
{
struct phy_device *phydev;
phydev = phy_create(&pdev->dev, NULL, &my_phy_driver);
if (IS_ERR(phydev)) {
printk(KERN_ERR "my_phy: failed to create PHY device\n");
return PTR_ERR(phydev);
}
phy_connect_direct(phydev, netdev);
return 0;
}
static int my_phy_remove(struct platform_device *pdev)
{
struct phy_device *phydev = platform_get_drvdata(pdev);
phy_disconnect(phydev);
phy_destroy(phydev);
return 0;
}
static struct platform_driver my_phy_platform_driver = {
.probe = my_phy_probe,
.remove = my_phy_remove,
.driver = {
.name = "my_phy_driver",
},
};
static struct platform_device my_phy_device = {
.name = "my_phy_device",
};
static int __init my_phy_init_module(void)
{
platform_device_register(&my_phy_device);
platform_driver_register(&my_phy_platform_driver);
return 0;
}
static void __exit my_phy_exit_module(void)
{
platform_driver_unregister(&my_phy_platform_driver);
platform_device_unregister(&my_phy_device);
}
module_init(my_phy_init_module);
module_exit(my_phy_exit_module);
MODULE_LICENSE("GPL");
设备树
/dts-v1/;
/ {
compatible = "my_board";
my_phy: phy@1 {
compatible = "my_phy_driver";
reg = <1>;
};
my_network_interface: ethernet@0 {
compatible = "my_network_interface";
reg = <0>;
phy-handle = <&my_phy>;
};
};