From 4c56b1434b814899c42a9d9f43d8265371282cd0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Mar 2024 11:40:36 +0100 Subject: [PATCH] pwm: Add a struct device to struct pwm_chip MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This replaces the formerly dynamically allocated struct device. This allows to additionally use it to track the lifetime of the struct pwm_chip. Otherwise the new struct device provides the same sysfs API as was provided by the dynamic device before. Link: https://lore.kernel.org/r/35c65ea7f6de789a568ff39d7b6b4ce80de4b7dc.1710670958.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König --- drivers/pwm/core.c | 93 +++++++++++++++++++++++++-------------------- include/linux/pwm.h | 5 ++- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 19386452e6c8..32871687c0a4 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -343,9 +343,16 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) if (!try_module_get(chip->owner)) return -ENODEV; + if (!get_device(&chip->dev)) { + err = -ENODEV; + goto err_get_device; + } + if (ops->request) { err = ops->request(chip, pwm); if (err) { + put_device(&chip->dev); +err_get_device: module_put(chip->owner); return err; } @@ -463,7 +470,7 @@ struct pwm_export { static inline struct pwm_chip *pwmchip_from_dev(struct device *pwmchip_dev) { - return dev_get_drvdata(pwmchip_dev); + return container_of(pwmchip_dev, struct pwm_chip, dev); } static inline struct pwm_export *pwmexport_from_dev(struct device *pwm_dev) @@ -941,46 +948,16 @@ static struct class pwm_class = { .pm = pm_sleep_ptr(&pwm_class_pm_ops), }; -static int pwmchip_sysfs_match(struct device *pwmchip_dev, const void *data) -{ - return pwmchip_from_dev(pwmchip_dev) == data; -} - -static void pwmchip_sysfs_export(struct pwm_chip *chip) -{ - struct device *pwmchip_dev; - - /* - * If device_create() fails the pwm_chip is still usable by - * the kernel it's just not exported. - */ - pwmchip_dev = device_create(&pwm_class, pwmchip_parent(chip), MKDEV(0, 0), chip, - "pwmchip%d", chip->id); - if (IS_ERR(pwmchip_dev)) { - dev_warn(pwmchip_parent(chip), - "device_create failed for pwm_chip sysfs export\n"); - } -} - static void pwmchip_sysfs_unexport(struct pwm_chip *chip) { - struct device *pwmchip_dev; unsigned int i; - pwmchip_dev = class_find_device(&pwm_class, NULL, chip, - pwmchip_sysfs_match); - if (!pwmchip_dev) - return; - for (i = 0; i < chip->npwm; i++) { struct pwm_device *pwm = &chip->pwms[i]; if (test_bit(PWMF_EXPORTED, &pwm->flags)) - pwm_unexport_child(pwmchip_dev, pwm); + pwm_unexport_child(&chip->dev, pwm); } - - put_device(pwmchip_dev); - device_unregister(pwmchip_dev); } #define PWMCHIP_ALIGN ARCH_DMA_MINALIGN @@ -993,13 +970,21 @@ static void *pwmchip_priv(struct pwm_chip *chip) /* This is the counterpart to pwmchip_alloc() */ void pwmchip_put(struct pwm_chip *chip) { - kfree(chip); + put_device(&chip->dev); } EXPORT_SYMBOL_GPL(pwmchip_put); +static void pwmchip_release(struct device *pwmchip_dev) +{ + struct pwm_chip *chip = pwmchip_from_dev(pwmchip_dev); + + kfree(chip); +} + struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv) { struct pwm_chip *chip; + struct device *pwmchip_dev; size_t alloc_size; unsigned int i; @@ -1010,10 +995,15 @@ struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t if (!chip) return ERR_PTR(-ENOMEM); - chip->dev = parent; chip->npwm = npwm; chip->uses_pwmchip_alloc = true; + pwmchip_dev = &chip->dev; + device_initialize(pwmchip_dev); + pwmchip_dev->class = &pwm_class; + pwmchip_dev->parent = parent; + pwmchip_dev->release = pwmchip_release; + pwmchip_set_drvdata(chip, pwmchip_priv(chip)); for (i = 0; i < chip->npwm; i++) { @@ -1115,21 +1105,34 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner) mutex_lock(&pwm_lock); ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); - if (ret < 0) { - mutex_unlock(&pwm_lock); - return ret; - } + if (ret < 0) + goto err_idr_alloc; chip->id = ret; - mutex_unlock(&pwm_lock); + dev_set_name(&chip->dev, "pwmchip%u", chip->id); if (IS_ENABLED(CONFIG_OF)) of_pwmchip_add(chip); - pwmchip_sysfs_export(chip); + ret = device_add(&chip->dev); + if (ret) + goto err_device_add; + + mutex_unlock(&pwm_lock); return 0; + +err_device_add: + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); + + idr_remove(&pwm_chips, chip->id); +err_idr_alloc: + + mutex_unlock(&pwm_lock); + + return ret; } EXPORT_SYMBOL_GPL(__pwmchip_add); @@ -1151,6 +1154,8 @@ void pwmchip_remove(struct pwm_chip *chip) idr_remove(&pwm_chips, chip->id); mutex_unlock(&pwm_lock); + + device_del(&chip->dev); } EXPORT_SYMBOL_GPL(pwmchip_remove); @@ -1520,6 +1525,8 @@ EXPORT_SYMBOL_GPL(pwm_get); */ void pwm_put(struct pwm_device *pwm) { + struct pwm_chip *chip = pwm->chip; + if (!pwm) return; @@ -1530,12 +1537,14 @@ void pwm_put(struct pwm_device *pwm) goto out; } - if (pwm->chip->ops->free) + if (chip->ops->free) pwm->chip->ops->free(pwm->chip, pwm); pwm->label = NULL; - module_put(pwm->chip->owner); + put_device(&chip->dev); + + module_put(chip->owner); out: mutex_unlock(&pwm_lock); } diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 78b9061572ff..495e23761f34 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -2,6 +2,7 @@ #ifndef __LINUX_PWM_H #define __LINUX_PWM_H +#include #include #include #include @@ -277,7 +278,7 @@ struct pwm_ops { * @pwms: array of PWM devices allocated by the framework */ struct pwm_chip { - struct device *dev; + struct device dev; const struct pwm_ops *ops; struct module *owner; unsigned int id; @@ -295,7 +296,7 @@ struct pwm_chip { static inline struct device *pwmchip_parent(const struct pwm_chip *chip) { - return chip->dev; + return chip->dev.parent; } static inline void *pwmchip_get_drvdata(struct pwm_chip *chip) -- 2.25.1