From b2d1e760dbb8c440b64b8910e18f87411a0551ec Mon Sep 17 00:00:00 2001 From: "minjie.yu" Date: Wed, 12 Jun 2024 09:54:15 +0800 Subject: [PATCH] pwm: add functions pwm_request() and pwm_free() Signed-off-by: minjie.yu --- Documentation/driver-api/pwm.rst | 9 +++-- drivers/pwm/core.c | 66 ++++++++++++++++++++++++++++++++ include/linux/pwm.h | 13 +++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index 3fdc95f7a1d1..7fd172274adc 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -35,9 +35,12 @@ consumers to providers, as given in the following example:: Using PWMs ---------- -Consumers use the pwm_get() function and pass to it the consumer device or a -consumer name. pwm_put() is used to free the PWM device. Managed variants of -the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. +Legacy users can request a PWM device using pwm_request() and free it +after usage with pwm_free(). + +New users should use the pwm_get() function and pass to it the consumer +device or a consumer name. pwm_put() is used to free the PWM device. Managed +variants of the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. After being requested, a PWM has to be configured using:: diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 0c8c63239adb..ef979bbef0d1 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,12 @@ static DEFINE_MUTEX(pwm_lock); static LIST_HEAD(pwm_chips); static DECLARE_BITMAP(allocated_pwms, MAX_PWMS); +static RADIX_TREE(pwm_tree, GFP_KERNEL); + +static struct pwm_device *pwm_to_device(unsigned int pwm) +{ + return radix_tree_lookup(&pwm_tree, pwm); +} /* Called with pwm_lock held */ static int alloc_pwms(unsigned int count) @@ -53,6 +60,14 @@ static int alloc_pwms(unsigned int count) /* Called with pwm_lock held */ static void free_pwms(struct pwm_chip *chip) { + unsigned int i; + + for (i = 0; i < chip->npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + + radix_tree_delete(&pwm_tree, pwm->pwm); + } + bitmap_clear(allocated_pwms, chip->base, chip->npwm); kfree(chip->pwms); @@ -293,6 +308,8 @@ int pwmchip_add(struct pwm_chip *chip) pwm->chip = chip; pwm->pwm = chip->base + i; pwm->hwpwm = i; + + radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } list_add(&chip->list, &pwm_chips); @@ -350,6 +367,43 @@ int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip) } EXPORT_SYMBOL_GPL(devm_pwmchip_add); +/** + * pwm_request() - request a PWM device + * @pwm: global PWM device index + * @label: PWM device label + * + * This function is deprecated, use pwm_get() instead. + * + * Returns: A pointer to a PWM device or an ERR_PTR()-encoded error code on + * failure. + */ +struct pwm_device *pwm_request(int pwm, const char *label) +{ + struct pwm_device *dev; + int err; + + if (pwm < 0 || pwm >= MAX_PWMS) + return ERR_PTR(-EINVAL); + + mutex_lock(&pwm_lock); + + dev = pwm_to_device(pwm); + if (!dev) { + dev = ERR_PTR(-EPROBE_DEFER); + goto out; + } + + err = pwm_device_request(dev, label); + if (err < 0) + dev = ERR_PTR(err); + +out: + mutex_unlock(&pwm_lock); + + return dev; +} +EXPORT_SYMBOL_GPL(pwm_request); + /** * pwm_request_from_chip() - request a PWM device relative to a PWM chip * @chip: PWM chip @@ -382,6 +436,18 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, } EXPORT_SYMBOL_GPL(pwm_request_from_chip); +/** + * pwm_free() - free a PWM device + * @pwm: PWM device + * + * This function is deprecated, use pwm_put() instead. + */ +void pwm_free(struct pwm_device *pwm) +{ + pwm_put(pwm); +} +EXPORT_SYMBOL_GPL(pwm_free); + static void pwm_apply_state_debug(struct pwm_device *pwm, const struct pwm_state *state) { diff --git a/include/linux/pwm.h b/include/linux/pwm.h index fe0f38ce1bde..14d52d94da44 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -309,6 +309,8 @@ struct pwm_chip { #if IS_ENABLED(CONFIG_PWM) /* PWM user APIs */ +struct pwm_device *pwm_request(int pwm_id, const char *label); +void pwm_free(struct pwm_device *pwm); int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state); int pwm_adjust_config(struct pwm_device *pwm); @@ -408,6 +410,17 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, struct fwnode_handle *fwnode, const char *con_id); #else +static inline struct pwm_device *pwm_request(int pwm_id, const char *label) +{ + might_sleep(); + return ERR_PTR(-ENODEV); +} + +static inline void pwm_free(struct pwm_device *pwm) +{ + might_sleep(); +} + static inline int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) { -- Gitee