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提供程式¶
PHY提供程式是指實現一個或多個PHY例項的實體。 對於PHY提供程式僅實現PHY的單個例項的簡單情況,該框架提供了of_phy_simple_xlate中of_xlate的自己的實現。 如果PHY提供程式實現多個例項,則應提供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,它將裝置和of_xlate作為引數。 對於dt啟動情況,所有PHY提供程式都應使用以上2個宏之一來註冊PHY提供程式。
通常,與PHY提供程式關聯的裝置樹節點將包含一組子節點,每個子節點代表一個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驅動程式可以使用以上2個API之一,透過傳遞裝置指標和phy ops來建立PHY。 phy_ops是一組函式指標,用於執行PHY操作,例如init,exit,power_on和power_off。
為了取消引用私有資料(在phy_ops中),phy提供程式驅動程式可以在建立PHY之後使用phy_set_drvdata(),並在phy_ops中使用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 可用於獲取PHY。 在dt啟動的情況下,字串引數應包含dt資料中給出的phy名稱,而在非dt啟動的情況下,應包含PHY的標籤。 兩個devm_phy_get 在成功的PHY獲取時,使用devres將裝置與PHY關聯。 在驅動程式分離時,將呼叫devres資料上的釋放函式,並釋放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。 也就是說,釋放呼叫,phy_init() 和 phy_exit() 呼叫,以及 phy_power_on() 和 phy_power_off() 呼叫在應用於NULL phy時都是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驅動程式可能不實現 phy_init() 或 phy_power_on(),但控制器應始終呼叫這些函式以與其他PHY相容。 一些PHY可能需要 phy_set_mode,而另一些可能使用預設模式(通常透過裝置樹或其他韌體配置)。 為了相容性,如果您知道將要使用的模式,則應始終呼叫此函式。 通常,此函式應在 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關聯的devres。
銷燬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 執行時¶
此子系統已啟用pm執行時。 因此,在建立PHY時,將呼叫此子系統建立的phy裝置的 pm_runtime_enable,而在銷燬PHY時,將呼叫 pm_runtime_disable。 請注意,此子系統建立的phy裝置將是呼叫 phy_create 的裝置的子裝置(PHY提供程式裝置)。
因此,由於父子關係,此子系統建立的phy_device的 pm_runtime_get_sync 將呼叫PHY提供程式裝置的 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 用於執行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