脈衝寬度調製 (PWM) 介面¶
提供有關 Linux PWM 介面的概述
PWM 通常用於控制手機中的 LED、風扇或振動器。具有固定用途的 PWM 不需要實現 Linux PWM API(儘管它們可以)。但是,PWM 通常作為 SoC 上的離散裝置存在,沒有固定用途。由電路板設計人員將它們連線到 LED 或風扇。為了提供這種靈活性,存在通用的 PWM API。
識別 PWM¶
傳統 PWM API 的使用者使用唯一 ID 來引用 PWM 裝置。
與透過唯一 ID 引用 PWM 裝置不同,電路板設定程式碼應註冊靜態對映,該對映可用於將 PWM 使用者與提供者匹配,如以下示例所示
static struct pwm_lookup board_pwm_lookup[] = {
PWM_LOOKUP("tegra-pwm", 0, "pwm-backlight", NULL,
50000, PWM_POLARITY_NORMAL),
};
static void __init board_init(void)
{
...
pwm_add_table(board_pwm_lookup, ARRAY_SIZE(board_pwm_lookup));
...
}
使用 PWM¶
使用者使用 pwm_get() 函式並將使用者裝置或使用者名稱傳遞給它。pwm_put() 用於釋放 PWM 裝置。getter 的託管變體 devm_pwm_get() 和 devm_fwnode_pwm_get() 也存在。
請求 PWM 後,必須使用以下方式進行配置
int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state);
此 API 控制 PWM 週期/佔空比配置以及啟用/停用狀態。
如果 PWM 不休眠,則可以在原子上下文中使用 PWM 裝置。 您可以使用以下方法檢查是否是這種情況
bool pwm_might_sleep(struct pwm_device *pwm);
如果為 false,也可以使用以下命令從原子上下文中配置 PWM
int pwm_apply_atomic(struct pwm_device *pwm, struct pwm_state *state);
作為使用者,不要依賴停用 PWM 的輸出狀態。 如果可能,驅動程式應該發出非活動狀態,但某些驅動程式無法做到。 如果您依賴於獲取非活動狀態,請使用 .duty_cycle=0,.enabled=true。
還有一個 usage_power 設定:如果設定,PWM 驅動程式只需要維護功率輸出,但在訊號形式方面有更大的自由度。 如果驅動程式支援,則可以最佳化訊號,例如透過相移晶片的各個通道來改善 EMI。
pwm_config()、pwm_enable() 和 pwm_disable() 函式只是 pwm_apply_might_sleep() 的包裝器,如果使用者想要一次更改多個引數,則不應使用。 例如,如果您在同一函式中看到 pwm_config() 和 pwm_{enable,disable}() 呼叫,這可能意味著您應該切換到 pwm_apply_might_sleep()。
PWM 使用者 API 還允許使用者使用 pwm_get_state() 查詢傳遞給 pwm_apply_might_sleep() 的上次呼叫的 PWM 狀態。 請注意,如果使用中的硬體無法完全滿足請求,這與驅動程式實際實現的不同。 目前沒有使用者可以獲取實際實施的設定的方法。
除了 PWM 狀態之外,PWM API 還公開了 PWM 引數,這些引數是應在此 PWM 上使用的參考 PWM 配置。 PWM 引數通常是平臺特定的,並允許 PWM 使用者僅關心相對於完整週期的佔空比(例如,佔空比 = 週期的 50%)。 struct pwm_args 包含 2 個欄位(週期和極性),應用於設定初始 PWM 配置(通常在 PWM 使用者的探測函式中完成)。 PWM 引數使用 pwm_get_args() 檢索。
所有使用者都應該在恢復時重新配置 PWM。 這是確保一切都以正確的順序恢復的唯一方法。
將 PWM 與 sysfs 介面一起使用¶
如果在核心配置中啟用了 CONFIG_SYSFS,則提供了一個簡單的 sysfs 介面,用於從使用者空間使用 PWM。 它在 /sys/class/pwm/ 中公開。 每個探測到的 PWM 控制器/晶片都將匯出為 pwmchipN,其中 N 是 PWM 晶片的基數。 在目錄中,您將找到
- npwm
此晶片支援的 PWM 通道數(只讀)。
- 匯出
匯出 PWM 通道以與 sysfs 一起使用(只寫)。
- 取消匯出
從 sysfs 取消匯出 PWM 通道(只寫)。
PWM 通道使用每個晶片的索引從 0 到 npwm-1 進行編號。
匯出 PWM 通道時,將在與其關聯的 pwmchipN 目錄中建立一個 pwmX 目錄,其中 X 是匯出的通道的編號。 然後可以使用以下屬性
- 週期
PWM 訊號的總週期(讀/寫)。 值的單位為納秒,是 PWM 的活動時間和非活動時間之和。
- 佔空比
PWM 訊號的活動時間(讀/寫)。 值的單位為納秒,並且必須小於或等於週期。
- 極性
更改 PWM 訊號的極性(讀/寫)。 只有當 PWM 晶片支援更改極性時,才能寫入此屬性。 值是字串“normal”或“inversed”。
- 啟用
啟用/停用 PWM 訊號(讀/寫)。
0 - 停用
1 - 啟用
實現 PWM 驅動程式¶
目前有兩種方法可以實現 PWM 驅動程式。 傳統上,只有 barebone API,這意味著每個驅動程式都必須自己實現 pwm_*() 函式。 這意味著系統中不可能有多個 PWM 驅動程式。 因此,新的驅動程式必須使用通用的 PWM 框架。
可以使用 pwmchip_alloc() 分配新的 PWM 控制器/晶片,然後使用 pwmchip_add() 註冊,並使用 pwmchip_remove() 再次刪除。 要撤消 pwmchip_alloc(),請使用 pwmchip_put()。 pwmchip_add() 將填充的 struct pwm_chip 作為引數,該引數提供 PWM 晶片的描述、晶片提供的 PWM 裝置數量以及框架支援的 PWM 操作的晶片特定實現。
在 PWM 驅動程式中實現極性支援時,請確保遵守 PWM 框架中的訊號約定。 根據定義,正常極性表示訊號在高電平時開始,持續佔空比的時間,然後在週期的剩餘時間內變為低電平。 相反,具有反向極性的訊號在低電平時開始,持續佔空比的時間,然後在週期的剩餘時間內變為高電平。
鼓勵驅動程式實現 ->apply(),而不是傳統的 ->enable()、->disable() 和 ->config() 方法。 這樣做應該在 PWM 配置工作流程中提供原子性,這在 PWM 控制關鍵裝置(如調節器)時是必需的。
還鼓勵實現 ->get_state()(用於檢索初始 PWM 狀態的方法),原因相同:讓 PWM 使用者瞭解當前的 PWM 狀態可以讓他避免故障。
驅動程式不應實現任何電源管理。 換句話說,使用者應按照“使用 PWM”部分中的描述來實現它。
鎖定¶
PWM 核心列表操作受互斥鎖保護,因此可能無法從原子上下文中呼叫 pwm_get() 和 pwm_put()。 目前,PWM 核心不強制任何鎖定到 pwm_enable()、pwm_disable() 和 pwm_config(),因此呼叫上下文當前是驅動程式特定的。 這是一個源自先前 barebone API 的問題,應儘快修復。
助手¶
目前,只能使用 period_ns 和 duty_ns 配置 PWM。 對於某些用例,freq_hz 和 duty_percent 可能更好。 請考慮將適當的助手新增到框架,而不是在驅動程式中進行計算。