--- zzzz-none-000/linux-3.10.107/drivers/pwm/core.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/pwm/core.c 2021-02-04 17:41:59.000000000 +0000 @@ -30,10 +30,9 @@ #include #include -#define MAX_PWMS 1024 +#include -/* flags in the third cell of the DT PWM specifier */ -#define PWM_SPEC_POLARITY (1 << 0) +#define MAX_PWMS 1024 static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); @@ -149,7 +148,7 @@ pwm_set_period(pwm, args->args[1]); - if (args->args[2] & PWM_SPEC_POLARITY) + if (args->args[2] & PWM_POLARITY_INVERTED) pwm_set_polarity(pwm, PWM_POLARITY_INVERSED); else pwm_set_polarity(pwm, PWM_POLARITY_NORMAL); @@ -193,7 +192,7 @@ static void of_pwmchip_remove(struct pwm_chip *chip) { - if (chip->dev && chip->dev->of_node) + if (chip->dev) of_node_put(chip->dev->of_node); } @@ -201,6 +200,8 @@ * pwm_set_chip_data() - set private chip data for a PWM * @pwm: PWM device * @data: pointer to chip-specific data + * + * Returns: 0 on success or a negative error code on failure. */ int pwm_set_chip_data(struct pwm_device *pwm, void *data) { @@ -216,6 +217,8 @@ /** * pwm_get_chip_data() - get private chip data for a PWM * @pwm: PWM device + * + * Returns: A pointer to the chip-private data for the PWM device. */ void *pwm_get_chip_data(struct pwm_device *pwm) { @@ -224,20 +227,25 @@ EXPORT_SYMBOL_GPL(pwm_get_chip_data); /** - * pwmchip_add() - register a new PWM chip + * pwmchip_add_with_polarity() - register a new PWM chip * @chip: the PWM chip to add + * @polarity: initial polarity of PWM channels * * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base - * will be used. + * will be used. The initial polarity for all channels is specified by the + * @polarity parameter. + * + * Returns: 0 on success or a negative error code on failure. */ -int pwmchip_add(struct pwm_chip *chip) +int pwmchip_add_with_polarity(struct pwm_chip *chip, + enum pwm_polarity polarity) { struct pwm_device *pwm; unsigned int i; int ret; if (!chip || !chip->dev || !chip->ops || !chip->ops->config || - !chip->ops->enable || !chip->ops->disable) + !chip->ops->enable || !chip->ops->disable || !chip->npwm) return -EINVAL; mutex_lock(&pwm_lock); @@ -260,6 +268,8 @@ pwm->chip = chip; pwm->pwm = chip->base + i; pwm->hwpwm = i; + pwm->polarity = polarity; + mutex_init(&pwm->lock); radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } @@ -274,10 +284,27 @@ if (IS_ENABLED(CONFIG_OF)) of_pwmchip_add(chip); + pwmchip_sysfs_export(chip); + out: mutex_unlock(&pwm_lock); return ret; } +EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity); + +/** + * pwmchip_add() - register a new PWM chip + * @chip: the PWM chip to add + * + * Register a new PWM chip. If chip->base < 0 then a dynamically assigned base + * will be used. The initial polarity for all channels is normal. + * + * Returns: 0 on success or a negative error code on failure. + */ +int pwmchip_add(struct pwm_chip *chip) +{ + return pwmchip_add_with_polarity(chip, PWM_POLARITY_NORMAL); +} EXPORT_SYMBOL_GPL(pwmchip_add); /** @@ -286,12 +313,16 @@ * * Removes a PWM chip. This function may return busy if the PWM chip provides * a PWM device that is still requested. + * + * Returns: 0 on success or a negative error code on failure. */ int pwmchip_remove(struct pwm_chip *chip) { unsigned int i; int ret = 0; + pwmchip_sysfs_unexport_children(chip); + mutex_lock(&pwm_lock); for (i = 0; i < chip->npwm; i++) { @@ -310,6 +341,8 @@ free_pwms(chip); + pwmchip_sysfs_unexport(chip); + out: mutex_unlock(&pwm_lock); return ret; @@ -318,10 +351,13 @@ /** * pwm_request() - request a PWM device - * @pwm_id: global PWM device index + * @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) { @@ -356,9 +392,9 @@ * @index: per-chip index of the PWM to request * @label: a literal description string of this PWM * - * Returns the PWM at the given index of the given PWM 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. + * Returns: A pointer to the PWM device at the given index of the given PWM + * 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, @@ -399,13 +435,24 @@ * @pwm: PWM device * @duty_ns: "on" time (in nanoseconds) * @period_ns: duration (in nanoseconds) of one cycle + * + * Returns: 0 on success or a negative error code on failure. */ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) { + int err; + if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns) return -EINVAL; - return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); + err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns); + if (err) + return err; + + pwm->duty_cycle = duty_ns; + pwm->period = period_ns; + + return 0; } EXPORT_SYMBOL_GPL(pwm_config); @@ -414,33 +461,64 @@ * @pwm: PWM device * @polarity: new polarity of the PWM signal * - * Note that the polarity cannot be configured while the PWM device is enabled + * Note that the polarity cannot be configured while the PWM device is + * enabled. + * + * Returns: 0 on success or a negative error code on failure. */ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) { + int err; + if (!pwm || !pwm->chip->ops) return -EINVAL; if (!pwm->chip->ops->set_polarity) return -ENOSYS; - if (test_bit(PWMF_ENABLED, &pwm->flags)) - return -EBUSY; + mutex_lock(&pwm->lock); + + if (pwm_is_enabled(pwm)) { + err = -EBUSY; + goto unlock; + } + + err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); + if (err) + goto unlock; + + pwm->polarity = polarity; - return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); +unlock: + mutex_unlock(&pwm->lock); + return err; } EXPORT_SYMBOL_GPL(pwm_set_polarity); /** * pwm_enable() - start a PWM output toggling * @pwm: PWM device + * + * Returns: 0 on success or a negative error code on failure. */ int pwm_enable(struct pwm_device *pwm) { - if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags)) - return pwm->chip->ops->enable(pwm->chip, pwm); + int err = 0; + + if (!pwm) + return -EINVAL; + + mutex_lock(&pwm->lock); - return pwm ? 0 : -EINVAL; + if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) { + err = pwm->chip->ops->enable(pwm->chip, pwm); + if (err) + clear_bit(PWMF_ENABLED, &pwm->flags); + } + + mutex_unlock(&pwm->lock); + + return err; } EXPORT_SYMBOL_GPL(pwm_enable); @@ -487,6 +565,9 @@ * lookup of the PWM index. This also means that the "pwm-names" property * becomes mandatory for devices that look up the PWM device via the con_id * parameter. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. */ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id) { @@ -553,7 +634,7 @@ * @table: array of consumers to register * @num: number of consumers in table */ -void __init pwm_add_table(struct pwm_lookup *table, size_t num) +void pwm_add_table(struct pwm_lookup *table, size_t num) { mutex_lock(&pwm_lookup_lock); @@ -566,6 +647,23 @@ } /** + * pwm_remove_table() - unregister PWM device consumers + * @table: array of consumers to unregister + * @num: number of consumers in table + */ +void pwm_remove_table(struct pwm_lookup *table, size_t num) +{ + mutex_lock(&pwm_lookup_lock); + + while (num--) { + list_del(&table->list); + table++; + } + + mutex_unlock(&pwm_lookup_lock); +} + +/** * pwm_get() - look up and request a PWM device * @dev: device for PWM consumer * @con_id: consumer name @@ -576,15 +674,17 @@ * * Once a PWM chip has been found the specified PWM device will be requested * and is ready to be used. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. */ struct pwm_device *pwm_get(struct device *dev, const char *con_id) { struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER); const char *dev_id = dev ? dev_name(dev) : NULL; struct pwm_chip *chip = NULL; - unsigned int index = 0; unsigned int best = 0; - struct pwm_lookup *p; + struct pwm_lookup *p, *chosen = NULL; unsigned int match; /* look up via DT first */ @@ -631,8 +731,7 @@ } if (match > best) { - chip = pwmchip_find_by_name(p->provider); - index = p->index; + chosen = p; if (match != 3) best = match; @@ -641,11 +740,24 @@ } } - if (chip) - pwm = pwm_request_from_chip(chip, index, con_id ?: dev_id); + if (!chosen) { + pwm = ERR_PTR(-ENODEV); + goto out; + } - mutex_unlock(&pwm_lookup_lock); + chip = pwmchip_find_by_name(chosen->provider); + if (!chip) + goto out; + pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id); + if (IS_ERR(pwm)) + goto out; + + pwm_set_period(pwm, chosen->period); + pwm_set_polarity(pwm, chosen->polarity); + +out: + mutex_unlock(&pwm_lookup_lock); return pwm; } EXPORT_SYMBOL_GPL(pwm_get); @@ -689,12 +801,15 @@ * * This function performs like pwm_get() but the acquired PWM device will * automatically be released on driver detach. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. */ struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id) { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); @@ -718,13 +833,16 @@ * * This function performs like of_pwm_get() but the acquired PWM device will * automatically be released on driver detach. + * + * Returns: A pointer to the requested PWM device or an ERR_PTR()-encoded + * error code on failure. */ struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np, const char *con_id) { struct pwm_device **ptr, *pwm; - ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL); + ptr = devres_alloc(devm_pwm_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); @@ -769,11 +887,11 @@ * pwm_can_sleep() - report whether PWM access will sleep * @pwm: PWM device * - * It returns true if accessing the PWM can sleep, false otherwise. + * Returns: True if accessing the PWM can sleep, false otherwise. */ bool pwm_can_sleep(struct pwm_device *pwm) { - return pwm->chip->can_sleep; + return true; } EXPORT_SYMBOL_GPL(pwm_can_sleep); @@ -788,12 +906,12 @@ seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label); if (test_bit(PWMF_REQUESTED, &pwm->flags)) - seq_printf(s, " requested"); + seq_puts(s, " requested"); - if (test_bit(PWMF_ENABLED, &pwm->flags)) - seq_printf(s, " enabled"); + if (pwm_is_enabled(pwm)) + seq_puts(s, " enabled"); - seq_printf(s, "\n"); + seq_puts(s, "\n"); } } @@ -861,6 +979,5 @@ return 0; } - subsys_initcall(pwm_debugfs_init); #endif /* CONFIG_DEBUG_FS */