brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · 0d74890 Raw
213 lines · plain
1.. SPDX-License-Identifier: GPL-2.02.. include:: ../../disclaimer-zh_CN.rst3 4:Original: Documentation/driver-api/phy/phy.rst5 6:翻译:7 8 司延腾 Yanteng Si <siyanteng@loongson.cn>9 10=========11PHY子系统12=========13 14:作者: Kishon Vijay Abraham I <kishon@ti.com>15 16本文档解释了 PHY 的通用框架和提供的API,以及使用方法。17 18简介19====20 21*PHY* 是物理层的缩写,它被用来把设备连接到一个物理媒介,例如USB控制器22有一个提供序列化、反序列化、编码、解码和负责获取所需的数据传输速率的 PHY。23注意,有些USB控制器内嵌了 PHY 的功能,其它的则使用了一个外置的PHY,此外24使用 PHY 的设备还有无线网、以太网、SATA等(控制器)。25 26创建这个框架的目的是将遍布 Linux 内核的 PHY 驱动程序融入到 drivers/phy,27以增加代码的可复用性,进而提高代码的可维护性。28 29该框架仅适用于使用外部 PHY(PHY 功能未嵌入控制器内)的设备。30 31注册/注销PHY provider32=====================33 34PHY provider是指实现一个或多个 PHY 实例的实体。对于 PHY provider 仅35实现单个 PHY 实例的简单情况,框架在 of_phy_simple_xlate 中提供其自己36的 of_xlate 实现。如果 PHY provider 实现多个实例,则应提供其自己的37of_xlate 实现。of_xlate 仅用于 dt 启动情况。38 39::40 41	#define of_phy_provider_register(dev, xlate)    \42		__of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))43 44	#define devm_of_phy_provider_register(dev, xlate)       \45		__devm_of_phy_provider_register((dev), NULL, THIS_MODULE,46						(xlate))47 48of_phy_provider_register 和 devm_of_phy_provider_register 宏49可用于注册 phy_provider,它以 device 和 of_xlate 作为参数。对于 dt50启动情况,所有 PHY provider 都应使用上述两个宏之一来注册 PHY provider。51 52与 PHY provider 关联的设备树节点通常包含一组子节点,每个子节点代表一个53PHY。某些绑定可能会为了上下文和可扩展性将子节点嵌套在特别的层级中,在这种54情况下,可以使用低级别的 of_phy_provider_register_full() 和55devm_of_phy_provider_register_full() 宏来覆盖包含子节点的节点。56 57::58 59	#define of_phy_provider_register_full(dev, children, xlate) \60		__of_phy_provider_register(dev, children, THIS_MODULE, xlate)61 62	#define devm_of_phy_provider_register_full(dev, children, xlate) \63		__devm_of_phy_provider_register_full(dev, children,64						     THIS_MODULE, xlate)65 66	void devm_of_phy_provider_unregister(struct device *dev,67		struct phy_provider *phy_provider);68	void of_phy_provider_unregister(struct phy_provider *phy_provider);69 70devm_of_phy_provider_unregister 和 of_phy_provider_unregister71可以被用来注销PHY.72 73创建PHY74=======75 76PHY 驱动程序应创建 PHY,以便其他外围(芯片)控制器能够使用它。PHY 框架77提供了 2 个 API 来创建 PHY。78 79::80 81	struct phy *phy_create(struct device *dev, struct device_node *node,82			       const struct phy_ops *ops);83	struct phy *devm_phy_create(struct device *dev,84				    struct device_node *node,85				    const struct phy_ops *ops);86 87PHY 驱动程序可以使用上述两个 API 之一,通过传递设备指针和 phy_ops88来创建 PHY。89 90phy_ops 是一组用于执行 PHY 操作(例如 init、exit、power_on 和91power_off)的函数指针。92 93在 phy_ops 中,PHY provider驱动程序在创建 PHY 后使用 phy_set_drvdata()94设置私有数据,使用 phy_get_drvdata() 获取私有数据。95 96获取对 PHY 的引用97=================98 99控制器必须先获取对 PHY 的引用,然后才能使用 PHY。此框架提供以下 API100来获取对 PHY 的引用。101 102::103 104	struct phy *phy_get(struct device *dev, const char *string);105	struct phy *devm_phy_get(struct device *dev, const char *string);106	struct phy *devm_phy_optional_get(struct device *dev,107					  const char *string);108	struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,109				    const char *con_id);110	struct phy *devm_of_phy_optional_get(struct device *dev,111					     struct device_node *np,112					     const char *con_id);113	struct phy *devm_of_phy_get_by_index(struct device *dev,114					     struct device_node *np,115					     int index);116 117phy_get、devm_phy_get 和 devm_phy_optional_get 可用于在 dt118启动的情况下获取 PHY,字符串参数应包含 dt 数据中给出的 phy 名称,在119非 dt 启动的情况下,它应包含 PHY 的标签。两个 devm_phy_get 在成功120获取 PHY 后使用 devres 将设备与 PHY 关联。在驱动程序分离时,将在121devres 数据上调用 release 函数并释放 devres 数据。当 phy 是可选122的时,应使用 _optional_get 变体。这些函数永远不会返回 -ENODEV,而123是在找不到 phy 时返回 NULL。一些通用驱动程序(例如 ehci)可能使用124多个 phy。在这种情况下,devm_of_phy_get 或 devm_of_phy_get_by_index125用于根据名称或索引获取 phy 引用。126 127需要注意的是,NULL 是有效的 phy 引用。NULL phy 上的所有 phy 使用128者调用都将成为 NOP。也就是说释放调用,当应用于 NULL phy 时,release129调用、phy_init()/phy_exit() 调用、phy_power_on()/phy_power_off()130调用都是 NOP。NULL phy 在处理可选的 phy 设备中很有用。131 132API的调用顺序133=============134 135通常,调用顺序应该是::136 137    [devm_][of_]phy_get()138    phy_init()139    phy_power_on()140    [phy_set_mode[_ext]()]141    ...142    phy_power_off()143    phy_exit()144    [[of_]phy_put()]145 146一些PHY驱动可能没有实现 :c:func:`phy_init` 或 :c:func:`phy_power_on`,147但是控制器应该总是调用这些函数以兼容其它PHY,有些PHY可能要求148:c:func:`phy_set_mode <phy_set_mode_ext>` 而其他 PHY 可能使用149默认模式(通常通过设备树或其他固件配置)。出于兼容性考虑,如果您知道将150使用哪种模式,则应始终调用此函数。通常,应在 :c:func:`phy_power_on`151之后调用此函数,尽管某些 PHY 驱动程序可能随时允许调用它。152 153释放对 PHY 的引用154=================155 156当控制器不再需要 PHY 时,它必须使用上一节中提到的 API 释放对已获得157的 PHY 的引用。PHY 框架提供了 2 个 API 来释放对 PHY 的引用。158 159::160 161	void phy_put(struct phy *phy);162	void devm_phy_put(struct device *dev, struct phy *phy);163 164这两个 API 都用于释放对 PHY 的引用,并且 devm_phy_put 会销毁与此165PHY 关联的设备资源。166 167销毁 PHY168========169 170当创建 PHY 的驱动程序被卸载时,它应该使用以下 2 个 API 之一销毁其创171建的 PHY::172 173	void phy_destroy(struct phy *phy);174	void devm_phy_destroy(struct device *dev, struct phy *phy);175 176这两个 API 都会销毁 PHY,并且 devm_phy_destroy 会销毁与此 PHY 关177联的 devres。178 179PM Runtime180==========181 182这个子系统启用了pm runtime。 所以,在创建PHY 时,将调用此子系统创建的183phy 设备的 pm_runtime_enable 函数,在销毁 PHY 时,将调用184pm_runtime_disable。请注意,此子系统创建的 phy 设备将是调用 phy_create185(PHY provider 设备)的设备的子设备。186 187因此,由于父子关系,此子系统创建的 phy_device 的 pm_runtime_get_sync188调用 PHY provider 设备的 pm_runtime_get_sync。还应注意,189phy_power_on 和 phy_power_off 分别执行 phy_pm_runtime_get_sync 和190phy_pm_runtime_put。有导出的 API,如 phy_pm_runtime_get、191phy_pm_runtime_get_sync、phy_pm_runtime_put、phy_pm_runtime_put_sync、192phy_pm_runtime_allow 和 phy_pm_runtime_forbid,用于执行 PM 操作。193 194PHY映射195=======196 197为了在没有 DeviceTree 帮助的情况下获取对 PHY 的引用,框架提供了可与198clkdev 进行比较的查找,允许将 clk 结构体绑定到设备。当 struct phy 的199句柄已存在时,可以在运行时进行查找。200 201该框架提供以下 API 用于注册和注销查找::202 203	int phy_create_lookup(struct phy *phy, const char *con_id,204			      const char *dev_id);205	void phy_remove_lookup(struct phy *phy, const char *con_id,206			       const char *dev_id);207 208DeviceTree绑定209==============210 211PHY dt 绑定的文档可以在以下位置找到 @212Documentation/devicetree/bindings/phy/phy-bindings.txt213