diff options
author | Uwe Kleine-König <u.kleine-koenig@baylibre.com> | 2025-04-30 13:56:00 +0200 |
---|---|---|
committer | Uwe Kleine-König <ukleinek@kernel.org> | 2025-05-07 11:48:35 +0200 |
commit | d041b76ac9fb9e60e7cdb0265ed9d8b6058a88bf (patch) | |
tree | 57b93c50fb563d4e95a9e6f88060737e345d6f03 | |
parent | 164c4ac754abaf9643815d09001cc7d81042d624 (diff) |
pwm: Formally describe the procedure used to pick a hardware waveform setting
This serves as specification for both, PWM consumers and the respective
callback for lowlevel drivers.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/d2916bfa70274961ded26b07ab6998c36b90e69a.1746010245.git.u.kleine-koenig@baylibre.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
-rw-r--r-- | drivers/pwm/core.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 5cf64b3a4cdf..4d842c692194 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -231,7 +231,9 @@ static int __pwm_write_waveform(struct pwm_chip *chip, struct pwm_device *pwm, c * * Usually all values passed in @wf are rounded down to the nearest possible * value (in the order period_length_ns, duty_length_ns and then - * duty_offset_ns). Only if this isn't possible, a value might grow. + * duty_offset_ns). Only if this isn't possible, a value might grow. See the + * documentation for pwm_set_waveform_might_sleep() for a more formal + * description. * * Returns: 0 on success, 1 if at least one value had to be rounded up or a * negative errno. @@ -411,6 +413,26 @@ static int __pwm_set_waveform(struct pwm_device *pwm, * possible/needed. In the above example requesting .period_length_ns = 94 and * @exact = true, you get the hardware configured with period = 93.5 ns. * + * Let C be the set of possible hardware configurations for a given PWM device, + * consisting of tuples (p, d, o) where p is the period length, d is the duty + * length and o the duty offset. + * + * The following algorithm is implemented to pick the hardware setting + * (p, d, o) ∈ C for a given request (p', d', o') with @exact = false:: + * + * p = max( { ṗ | ∃ ḋ, ȯ : (ṗ, ḋ, ȯ) ∈ C ∧ ṗ ≤ p' } ∪ { min({ ṗ | ∃ ḋ, ȯ : (ṗ, ḋ, ȯ) ∈ C }) }) + * d = max( { ḋ | ∃ ȯ : (p, ḋ, ȯ) ∈ C ∧ ḋ ≤ d' } ∪ { min({ ḋ | ∃ ȯ : (p, ḋ, ȯ) ∈ C }) }) + * o = max( { ȯ | (p, d, ȯ) ∈ C ∧ ȯ ≤ o' } ∪ { min({ ȯ | (p, d, ȯ) ∈ C }) }) + * + * In words: The chosen period length is the maximal possible period length not + * bigger than the requested period length and if that doesn't exist, the + * minimal period length. The chosen duty length is the maximal possible duty + * length that is compatible with the chosen period length and isn't bigger than + * the requested duty length. Again if such a value doesn't exist, the minimal + * duty length compatible with the chosen period is picked. After that the duty + * offset compatible with the chosen period and duty length is chosen in the + * same way. + * * Returns: 0 on success, -EDOM if setting failed due to the exact waveform not * being possible (if @exact), or a different negative errno on failure. * Context: May sleep. |