diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-07-15 17:42:28 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-07-15 17:42:28 -0700 |
commit | c6e63a9882c90f753b11c82db4308a9aba94e38d (patch) | |
tree | d8a1040dcb88407922c4fc176888c9a7c73865c1 /drivers/pwm/core.c | |
parent | 500a711df663adccb30fd3508960ff90c73f1cd4 (diff) | |
parent | 240b129d597cb8a8880eb3a381ff10eb98ca0c07 (diff) |
Merge tag 'pwm/for-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux
Pull pwm updates from Uwe Kleine-König:
"This contains the usual mix of fixes, cleanups, two new drivers and
several dt binding updates. The fixes are for minor issues that are
already old (4.11-rc1 and 3.9-rc1) and were found by code review and
not during usage, so I didn't sent them for earlier inclusion.
The changes to include/linux/mfd/stm32-timers.h and
drivers/counter/stm32-timer-cnt.c are part of an immutable branch that
will also be included in the mfd and counter pulls. It changes some
register definitions and affects the pwm-stm32 driver.
Thanks go to Andy Shevchenko, AngeloGioacchino Del Regno, Conor
Dooley, David Lechner, Dhruva Gole, Drew Fustini, Frank Li, Jeff
Johnson, Junyi Zhao, Kelvin Zhang, Krzysztof Kozlowski, Lee Jones,
Linus Walleij, Linus Walleij, Michael Hennerich, Nicola Di Lieto,
Nicolas Ferre, Nuno Sa, Paul Cercueil, Raag Jadav, Rob Herring, Sean
Anderson, Sean Young, Shenwei Wang, Stefan Wahren, Trevor Gamblin,
Tzung-Bi Shih, Vincent Whitchurch and William Breathitt Gray for their
contributions to this pull request; they authored changes, spend time
reviewing changes and coordinated the above mentioned immutable
branch"
* tag 'pwm/for-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux: (38 commits)
pwm: axi-pwmgen: add .max_register to regmap
dt-bindings: pwm: at91: Add sama7d65 compatible string
pwm: atmel-tcb: Make private data variable naming consistent
pwm: atmel-tcb: Simplify checking the companion output
pwm: Allow pwm state transitions from an invalid state
pwm: xilinx: Simplify using devm_ functions
pwm: Use guards for pwm_lookup_lock instead of explicity mutex_lock + mutex_unlock
pwm: Use guards for export->lock instead of explicity mutex_lock + mutex_unlock
pwm: Use guards for pwm_lock instead of explicity mutex_lock + mutex_unlock
pwm: Register debugfs operations after the pwm class
pwm: imx-tpm: Enable pinctrl setting for sleep state
pwm: lpss: drop redundant runtime PM handles
pwm: lpss: use devm_pm_runtime_enable() helper
pwm-stm32: Make use of parametrised register definitions
dt-bindings: pwm: imx: remove interrupt property from required
pwm: meson: Add support for Amlogic S4 PWM
pwm: Add GPIO PWM driver
dt-bindings: pwm: Add pwm-gpio
pwm: Drop pwm_apply_state()
bus: ts-nbus: Use pwm_apply_might_sleep()
...
Diffstat (limited to 'drivers/pwm/core.c')
-rw-r--r-- | drivers/pwm/core.c | 181 |
1 files changed, 96 insertions, 85 deletions
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 18574857641e..8acbcf5b6673 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -6,6 +6,8 @@ * Copyright (C) 2011-2012 Avionic Design GmbH */ +#define DEFAULT_SYMBOL_NAMESPACE PWM + #include <linux/acpi.h> #include <linux/module.h> #include <linux/idr.h> @@ -135,6 +137,25 @@ static void pwm_apply_debug(struct pwm_device *pwm, } } +static bool pwm_state_valid(const struct pwm_state *state) +{ + /* + * For a disabled state all other state description is irrelevant and + * and supposed to be ignored. So also ignore any strange values and + * consider the state ok. + */ + if (state->enabled) + return true; + + if (!state->period) + return false; + + if (state->duty_cycle > state->period) + return false; + + return true; +} + /** * __pwm_apply() - atomically apply a new state to a PWM device * @pwm: PWM device @@ -145,9 +166,25 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) struct pwm_chip *chip; int err; - if (!pwm || !state || !state->period || - state->duty_cycle > state->period) + if (!pwm || !state) + return -EINVAL; + + if (!pwm_state_valid(state)) { + /* + * Allow to transition from one invalid state to another. + * This ensures that you can e.g. change the polarity while + * the period is zero. (This happens on stm32 when the hardware + * is in its poweron default state.) This greatly simplifies + * working with the sysfs API where you can only change one + * parameter at a time. + */ + if (!pwm_state_valid(&pwm->state)) { + pwm->state = *state; + return 0; + } + return -EINVAL; + } chip = pwm->chip; @@ -291,19 +328,15 @@ EXPORT_SYMBOL_GPL(pwm_adjust_config); int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, unsigned long timeout) { - int err; - if (!pwm || !pwm->chip->ops) return -EINVAL; if (!pwm->chip->ops->capture) return -ENOSYS; - mutex_lock(&pwm_lock); - err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout); - mutex_unlock(&pwm_lock); + guard(mutex)(&pwm_lock); - return err; + return pwm->chip->ops->capture(pwm->chip, pwm, result, timeout); } EXPORT_SYMBOL_GPL(pwm_capture); @@ -315,19 +348,15 @@ static struct pwm_chip *pwmchip_find_by_name(const char *name) if (!name) return NULL; - mutex_lock(&pwm_lock); + guard(mutex)(&pwm_lock); idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) { const char *chip_name = dev_name(pwmchip_parent(chip)); - if (chip_name && strcmp(chip_name, name) == 0) { - mutex_unlock(&pwm_lock); + if (chip_name && strcmp(chip_name, name) == 0) return chip; - } } - mutex_unlock(&pwm_lock); - return NULL; } @@ -394,9 +423,9 @@ err_get_device: * chip. A negative error code is returned if the index is not valid for the * specified PWM chip or if the PWM device cannot be requested. */ -struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, - unsigned int index, - const char *label) +static struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, + unsigned int index, + const char *label) { struct pwm_device *pwm; int err; @@ -404,18 +433,16 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, if (!chip || index >= chip->npwm) return ERR_PTR(-EINVAL); - mutex_lock(&pwm_lock); + guard(mutex)(&pwm_lock); + pwm = &chip->pwms[index]; err = pwm_device_request(pwm, label); if (err < 0) - pwm = ERR_PTR(err); + return ERR_PTR(err); - mutex_unlock(&pwm_lock); return pwm; } -EXPORT_SYMBOL_GPL(pwm_request_from_chip); - struct pwm_device * of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) @@ -511,11 +538,11 @@ static ssize_t period_store(struct device *pwm_dev, if (ret) return ret; - mutex_lock(&export->lock); + guard(mutex)(&export->lock); + pwm_get_state(pwm, &state); state.period = val; ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); return ret ? : size; } @@ -546,11 +573,11 @@ static ssize_t duty_cycle_store(struct device *pwm_dev, if (ret) return ret; - mutex_lock(&export->lock); + guard(mutex)(&export->lock); + pwm_get_state(pwm, &state); state.duty_cycle = val; ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); return ret ? : size; } @@ -580,7 +607,7 @@ static ssize_t enable_store(struct device *pwm_dev, if (ret) return ret; - mutex_lock(&export->lock); + guard(mutex)(&export->lock); pwm_get_state(pwm, &state); @@ -592,14 +619,11 @@ static ssize_t enable_store(struct device *pwm_dev, state.enabled = true; break; default: - ret = -EINVAL; - goto unlock; + return -EINVAL; } ret = pwm_apply_might_sleep(pwm, &state); -unlock: - mutex_unlock(&export->lock); return ret ? : size; } @@ -643,11 +667,11 @@ static ssize_t polarity_store(struct device *pwm_dev, else return -EINVAL; - mutex_lock(&export->lock); + guard(mutex)(&export->lock); + pwm_get_state(pwm, &state); state.polarity = polarity; ret = pwm_apply_might_sleep(pwm, &state); - mutex_unlock(&export->lock); return ret ? : size; } @@ -1102,11 +1126,11 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner) chip->owner = owner; - mutex_lock(&pwm_lock); + guard(mutex)(&pwm_lock); ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); if (ret < 0) - goto err_idr_alloc; + return ret; chip->id = ret; @@ -1119,8 +1143,6 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner) if (ret) goto err_device_add; - mutex_unlock(&pwm_lock); - return 0; err_device_add: @@ -1128,9 +1150,6 @@ err_device_add: of_pwmchip_remove(chip); idr_remove(&pwm_chips, chip->id); -err_idr_alloc: - - mutex_unlock(&pwm_lock); return ret; } @@ -1149,11 +1168,8 @@ void pwmchip_remove(struct pwm_chip *chip) if (IS_ENABLED(CONFIG_OF)) of_pwmchip_remove(chip); - mutex_lock(&pwm_lock); - - idr_remove(&pwm_chips, chip->id); - - mutex_unlock(&pwm_lock); + scoped_guard(mutex, &pwm_lock) + idr_remove(&pwm_chips, chip->id); device_del(&chip->dev); } @@ -1209,15 +1225,11 @@ static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode) struct pwm_chip *chip; unsigned long id, tmp; - mutex_lock(&pwm_lock); + guard(mutex)(&pwm_lock); idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) - if (pwmchip_parent(chip) && device_match_fwnode(pwmchip_parent(chip), fwnode)) { - mutex_unlock(&pwm_lock); + if (pwmchip_parent(chip) && device_match_fwnode(pwmchip_parent(chip), fwnode)) return chip; - } - - mutex_unlock(&pwm_lock); return ERR_PTR(-EPROBE_DEFER); } @@ -1366,14 +1378,12 @@ static LIST_HEAD(pwm_lookup_list); */ void pwm_add_table(struct pwm_lookup *table, size_t num) { - mutex_lock(&pwm_lookup_lock); + guard(mutex)(&pwm_lookup_lock); while (num--) { list_add_tail(&table->list, &pwm_lookup_list); table++; } - - mutex_unlock(&pwm_lookup_lock); } /** @@ -1383,14 +1393,12 @@ void pwm_add_table(struct pwm_lookup *table, size_t num) */ void pwm_remove_table(struct pwm_lookup *table, size_t num) { - mutex_lock(&pwm_lookup_lock); + guard(mutex)(&pwm_lookup_lock); while (num--) { list_del(&table->list); table++; } - - mutex_unlock(&pwm_lookup_lock); } /** @@ -1451,36 +1459,33 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) * Then we take the most specific entry - with the following order * of precedence: dev+con > dev only > con only. */ - mutex_lock(&pwm_lookup_lock); - - list_for_each_entry(p, &pwm_lookup_list, list) { - match = 0; + scoped_guard(mutex, &pwm_lookup_lock) + list_for_each_entry(p, &pwm_lookup_list, list) { + match = 0; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; + if (p->dev_id) { + if (!dev_id || strcmp(p->dev_id, dev_id)) + continue; - match += 2; - } + match += 2; + } - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; + if (p->con_id) { + if (!con_id || strcmp(p->con_id, con_id)) + continue; - match += 1; - } + match += 1; + } - if (match > best) { - chosen = p; + if (match > best) { + chosen = p; - if (match != 3) - best = match; - else - break; + if (match != 3) + best = match; + else + break; + } } - } - - mutex_unlock(&pwm_lookup_lock); if (!chosen) return ERR_PTR(-ENODEV); @@ -1532,11 +1537,11 @@ void pwm_put(struct pwm_device *pwm) chip = pwm->chip; - mutex_lock(&pwm_lock); + guard(mutex)(&pwm_lock); if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) { pr_warn("PWM device already freed\n"); - goto out; + return; } if (chip->ops->free) @@ -1547,8 +1552,6 @@ void pwm_put(struct pwm_device *pwm) put_device(&chip->dev); module_put(chip->owner); -out: - mutex_unlock(&pwm_lock); } EXPORT_SYMBOL_GPL(pwm_put); @@ -1705,9 +1708,17 @@ DEFINE_SEQ_ATTRIBUTE(pwm_debugfs); static int __init pwm_init(void) { + int ret; + + ret = class_register(&pwm_class); + if (ret) { + pr_err("Failed to initialize PWM class (%pe)\n", ERR_PTR(ret)); + return ret; + } + if (IS_ENABLED(CONFIG_DEBUG_FS)) debugfs_create_file("pwm", 0444, NULL, NULL, &pwm_debugfs_fops); - return class_register(&pwm_class); + return 0; } subsys_initcall(pwm_init); |