diff options
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); |