.. SPDX-License-Identifier: GPL-2.0 .. include:: ../../disclaimer-zh_CN.rst :Original: Documentation/driver-api/phy/phy.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> ========= PHYå系统 ========= :作者: Kishon Vijay Abraham I <kishon@ti.com> 本文档解释了 PHY 的通用框架和æä¾›çš„API,以åŠä½¿ç”¨æ–¹æ³•。 简介 ==== *PHY* 是物ç†å±‚çš„ç¼©å†™ï¼Œå®ƒè¢«ç”¨æ¥æŠŠè®¾å¤‡è¿žæŽ¥åˆ°ä¸€ä¸ªç‰©ç†åª’介,例如USB控制器 有一个æä¾›åºåˆ—化ã€ååºåˆ—化ã€ç¼–ç ã€è§£ç å’Œè´Ÿè´£èŽ·å–æ‰€éœ€çš„æ•°æ®ä¼ 输速率的 PHY。 注æ„,有些USB控制器内嵌了 PHY 的功能,其它的则使用了一个外置的PHY,æ¤å¤– 使用 PHY çš„è®¾å¤‡è¿˜æœ‰æ— çº¿ç½‘ã€ä»¥å¤ªç½‘ã€SATAç‰ï¼ˆæŽ§åˆ¶å™¨ï¼‰ã€‚ 创建这个框架的目的是将é布 Linux å†…æ ¸çš„ PHY 驱动程åºèžå…¥åˆ° drivers/phy, ä»¥å¢žåŠ ä»£ç çš„å¯å¤ç”¨æ€§ï¼Œè¿›è€Œæé«˜ä»£ç çš„å¯ç»´æŠ¤æ€§ã€‚ 该框架仅适用于使用外部 PHY(PHY 功能未嵌入控制器内)的设备。 注册/注销PHY provider ===================== PHY provider是指实现一个或多个 PHY 实例的实体。对于 PHY provider ä»… 实现å•个 PHY å®žä¾‹çš„ç®€å•æƒ…况,框架在 of_phy_simple_xlate ä¸æä¾›å…¶è‡ªå·± çš„ of_xlate 实现。如果 PHY provider 实现多个实例,则应æä¾›å…¶è‡ªå·±çš„ of_xlate 实现。of_xlate 仅用于 dt å¯åŠ¨æƒ…å†µã€‚ :: #define of_phy_provider_register(dev, xlate) \ __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) #define devm_of_phy_provider_register(dev, xlate) \ __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) of_phy_provider_register å’Œ devm_of_phy_provider_register å® å¯ç”¨äºŽæ³¨å†Œ phy_provider,它以 device å’Œ of_xlate ä½œä¸ºå‚æ•°ã€‚对于 dt å¯åŠ¨æƒ…å†µï¼Œæ‰€æœ‰ PHY provider 都应使用上述两个å®ä¹‹ä¸€æ¥æ³¨å†Œ PHY provider。 与 PHY provider å…³è”çš„è®¾å¤‡æ ‘èŠ‚ç‚¹é€šå¸¸åŒ…å«ä¸€ç»„å节点,æ¯ä¸ªå节点代表一个 PHY。æŸäº›ç»‘定å¯èƒ½ä¼šä¸ºäº†ä¸Šä¸‹æ–‡å’Œå¯æ‰©å±•性将å节点嵌套在特别的层级ä¸ï¼Œåœ¨è¿™ç§ 情况下,å¯ä»¥ä½¿ç”¨ä½Žçº§åˆ«çš„ of_phy_provider_register_full() å’Œ devm_of_phy_provider_register_full() 宿¥è¦†ç›–包å«å节点的节点。 :: #define of_phy_provider_register_full(dev, children, xlate) \ __of_phy_provider_register(dev, children, THIS_MODULE, xlate) #define devm_of_phy_provider_register_full(dev, children, xlate) \ __devm_of_phy_provider_register_full(dev, children, THIS_MODULE, xlate) void devm_of_phy_provider_unregister(struct device *dev, struct phy_provider *phy_provider); void of_phy_provider_unregister(struct phy_provider *phy_provider); devm_of_phy_provider_unregister å’Œ of_phy_provider_unregister å¯ä»¥è¢«ç”¨æ¥æ³¨é”€PHY. 创建PHY ======= PHY 驱动程åºåº”创建 PHY,以便其他外围(芯片)控制器能够使用它。PHY 框架 æä¾›äº† 2 个 API æ¥åˆ›å»º PHY。 :: struct phy *phy_create(struct device *dev, struct device_node *node, const struct phy_ops *ops); struct phy *devm_phy_create(struct device *dev, struct device_node *node, const struct phy_ops *ops); PHY 驱动程åºå¯ä»¥ä½¿ç”¨ä¸Šè¿°ä¸¤ä¸ª API ä¹‹ä¸€ï¼Œé€šè¿‡ä¼ é€’è®¾å¤‡æŒ‡é’ˆå’Œ phy_ops æ¥åˆ›å»º PHY。 phy_ops 是一组用于执行 PHY æ“作(例如 initã€exitã€power_on å’Œ power_off)的函数指针。 在 phy_ops ä¸ï¼ŒPHY provider驱动程åºåœ¨åˆ›å»º PHY åŽä½¿ç”¨ phy_set_drvdata() è®¾ç½®ç§æœ‰æ•°æ®ï¼Œä½¿ç”¨ phy_get_drvdata() 获å–ç§æœ‰æ•°æ®ã€‚ 获å–对 PHY 的引用 ================= 控制器必须先获å–对 PHY çš„å¼•ç”¨ï¼Œç„¶åŽæ‰èƒ½ä½¿ç”¨ PHYã€‚æ¤æ¡†æž¶æä¾›ä»¥ä¸‹ API æ¥èŽ·å–对 PHY 的引用。 :: struct phy *phy_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_optional_get(struct device *dev, const char *string); struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, const char *con_id); struct phy *devm_of_phy_optional_get(struct device *dev, struct device_node *np, const char *con_id); struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np, int index); phy_getã€devm_phy_get å’Œ devm_phy_optional_get å¯ç”¨äºŽåœ¨ dt å¯åŠ¨çš„æƒ…å†µä¸‹èŽ·å– PHY,å—ç¬¦ä¸²å‚æ•°åº”åŒ…å« dt æ•°æ®ä¸ç»™å‡ºçš„ phy å称,在 éž dt å¯åŠ¨çš„æƒ…å†µä¸‹ï¼Œå®ƒåº”åŒ…å« PHY çš„æ ‡ç¾ã€‚两个 devm_phy_get 在æˆåŠŸ èŽ·å– PHY åŽä½¿ç”¨ devres 将设备与 PHY å…³è”。在驱动程åºåˆ†ç¦»æ—¶ï¼Œå°†åœ¨ devres æ•°æ®ä¸Šè°ƒç”¨ release 函数并释放 devres æ•°æ®ã€‚当 phy 是å¯é€‰ 的时,应使用 _optional_get å˜ä½“。这些函数永远ä¸ä¼šè¿”回 -ENODEV,而 是在找ä¸åˆ° phy 时返回 NULL。一些通用驱动程åºï¼ˆä¾‹å¦‚ ehci)å¯èƒ½ä½¿ç”¨ 多个 phyã€‚åœ¨è¿™ç§æƒ…况下,devm_of_phy_get 或 devm_of_phy_get_by_index ç”¨äºŽæ ¹æ®åç§°æˆ–ç´¢å¼•èŽ·å– phy 引用。 éœ€è¦æ³¨æ„的是,NULL 是有效的 phy 引用。NULL phy 上的所有 phy 使用 者调用都将æˆä¸º NOP。也就是说释放调用,当应用于 NULL phy 时,release 调用ã€phy_init()/phy_exit() 调用ã€phy_power_on()/phy_power_off() 调用都是 NOP。NULL phy 在处ç†å¯é€‰çš„ phy 设备ä¸å¾ˆæœ‰ç”¨ã€‚ APIçš„è°ƒç”¨é¡ºåº ============= 通常,调用顺åºåº”该是:: [devm_][of_]phy_get() phy_init() phy_power_on() [phy_set_mode[_ext]()] ... phy_power_off() phy_exit() [[of_]phy_put()] 一些PHY驱动å¯èƒ½æ²¡æœ‰å®žçް :c:func:`phy_init` 或 :c:func:`phy_power_on`, 但是控制器应该总是调用这些函数以兼容其它PHY,有些PHYå¯èƒ½è¦æ±‚ :c:func:`phy_set_mode <phy_set_mode_ext>` 而其他 PHY å¯èƒ½ä½¿ç”¨ 默认模å¼ï¼ˆé€šå¸¸é€šè¿‡è®¾å¤‡æ ‘或其他固件é…置)。出于兼容性考虑,如果您知é“å°† ä½¿ç”¨å“ªç§æ¨¡å¼ï¼Œåˆ™åº”始终调用æ¤å‡½æ•°ã€‚通常,应在 :c:func:`phy_power_on` 之åŽè°ƒç”¨æ¤å‡½æ•°ï¼Œå°½ç®¡æŸäº› PHY 驱动程åºå¯èƒ½éšæ—¶å…许调用它。 释放对 PHY 的引用 ================= 当控制器ä¸å†éœ€è¦ PHY æ—¶ï¼Œå®ƒå¿…é¡»ä½¿ç”¨ä¸Šä¸€èŠ‚ä¸æåˆ°çš„ API 释放对已获得 çš„ PHY 的引用。PHY 框架æä¾›äº† 2 个 API æ¥é‡Šæ”¾å¯¹ PHY 的引用。 :: void phy_put(struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); 这两个 API 都用于释放对 PHY 的引用,并且 devm_phy_put 会销æ¯ä¸Žæ¤ PHY å…³è”的设备资æºã€‚ é”€æ¯ PHY ======== 当创建 PHY 的驱动程åºè¢«å¸è½½æ—¶ï¼Œå®ƒåº”该使用以下 2 个 API 之一销æ¯å…¶åˆ› 建的 PHY:: void phy_destroy(struct phy *phy); void devm_phy_destroy(struct device *dev, struct phy *phy); 这两个 API éƒ½ä¼šé”€æ¯ PHY,并且 devm_phy_destroy 会销æ¯ä¸Žæ¤ PHY å…³ è”çš„ devres。 PM Runtime ========== 这个å系统å¯ç”¨äº†pm runtime。 所以,在创建PHY 时,将调用æ¤å系统创建的 phy 设备的 pm_runtime_enable å‡½æ•°ï¼Œåœ¨é”€æ¯ PHY 时,将调用 pm_runtime_disable。请注æ„,æ¤å系统创建的 phy 设备将是调用 phy_create (PHY provider 设备)的设备的å设备。 å› æ¤ï¼Œç”±äºŽçˆ¶å关系,æ¤å系统创建的 phy_device çš„ pm_runtime_get_sync 调用 PHY provider 设备的 pm_runtime_get_sync。还应注æ„, phy_power_on å’Œ phy_power_off 分别执行 phy_pm_runtime_get_sync å’Œ phy_pm_runtime_put。有导出的 API,如 phy_pm_runtime_get〠phy_pm_runtime_get_syncã€phy_pm_runtime_putã€phy_pm_runtime_put_sync〠phy_pm_runtime_allow å’Œ phy_pm_runtime_forbid,用于执行 PM æ“作。 PHYæ˜ å°„ ======= 为了在没有 DeviceTree 帮助的情况下获å–对 PHY 的引用,框架æä¾›äº†å¯ä¸Ž clkdev 进行比较的查找,å…许将 clk 结构体绑定到设备。当 struct phy çš„ 奿Ÿ„å·²å˜åœ¨æ—¶ï¼Œå¯ä»¥åœ¨è¿è¡Œæ—¶è¿›è¡ŒæŸ¥æ‰¾ã€‚ 该框架æä¾›ä»¥ä¸‹ API 用于注册和注销查找:: int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id); void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id); DeviceTree绑定 ============== PHY dt 绑定的文档å¯ä»¥åœ¨ä»¥ä¸‹ä½ç½®æ‰¾åˆ° @ Documentation/devicetree/bindings/phy/phy-bindings.txt