From 76047c0312414915035f4ebbaa533fe3817a21e0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 3 Jun 2024 07:08:49 +0200 Subject: Adding upstream version 6.8.12. Signed-off-by: Daniel Baumann --- drivers/pwm/core.c | 852 ++++++++++++++++++++++----------------------- drivers/pwm/pwm-clps711x.c | 1 - drivers/pwm/pwm-cros-ec.c | 1 - drivers/pwm/pwm-meson.c | 51 +-- drivers/pwm/pwm-pxa.c | 4 +- drivers/pwm/pwm-sti.c | 46 +-- drivers/pwm/sysfs.c | 4 +- 7 files changed, 455 insertions(+), 504 deletions(-) (limited to 'drivers/pwm') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index f2728ee787..9d2dc5e1c8 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -24,277 +24,358 @@ #define CREATE_TRACE_POINTS #include -static DEFINE_MUTEX(pwm_lookup_lock); -static LIST_HEAD(pwm_lookup_list); - /* protects access to pwm_chips */ static DEFINE_MUTEX(pwm_lock); static DEFINE_IDR(pwm_chips); -static struct pwm_chip *pwmchip_find_by_name(const char *name) +static void pwm_apply_debug(struct pwm_device *pwm, + const struct pwm_state *state) { - struct pwm_chip *chip; - unsigned long id, tmp; - - if (!name) - return NULL; - - mutex_lock(&pwm_lock); + struct pwm_state *last = &pwm->last; + struct pwm_chip *chip = pwm->chip; + struct pwm_state s1 = { 0 }, s2 = { 0 }; + int err; - idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) { - const char *chip_name = dev_name(chip->dev); + if (!IS_ENABLED(CONFIG_PWM_DEBUG)) + return; - if (chip_name && strcmp(chip_name, name) == 0) { - mutex_unlock(&pwm_lock); - return chip; - } - } + /* No reasonable diagnosis possible without .get_state() */ + if (!chip->ops->get_state) + return; - mutex_unlock(&pwm_lock); + /* + * *state was just applied. Read out the hardware state and do some + * checks. + */ - return NULL; -} + err = chip->ops->get_state(chip, pwm, &s1); + trace_pwm_get(pwm, &s1, err); + if (err) + /* If that failed there isn't much to debug */ + return; -static int pwm_device_request(struct pwm_device *pwm, const char *label) -{ - int err; - struct pwm_chip *chip = pwm->chip; - const struct pwm_ops *ops = chip->ops; + /* + * The lowlevel driver either ignored .polarity (which is a bug) or as + * best effort inverted .polarity and fixed .duty_cycle respectively. + * Undo this inversion and fixup for further tests. + */ + if (s1.enabled && s1.polarity != state->polarity) { + s2.polarity = state->polarity; + s2.duty_cycle = s1.period - s1.duty_cycle; + s2.period = s1.period; + s2.enabled = s1.enabled; + } else { + s2 = s1; + } - if (test_bit(PWMF_REQUESTED, &pwm->flags)) - return -EBUSY; + if (s2.polarity != state->polarity && + state->duty_cycle < state->period) + dev_warn(pwmchip_parent(chip), ".apply ignored .polarity\n"); - if (!try_module_get(chip->owner)) - return -ENODEV; + if (state->enabled && + last->polarity == state->polarity && + last->period > s2.period && + last->period <= state->period) + dev_warn(pwmchip_parent(chip), + ".apply didn't pick the best available period (requested: %llu, applied: %llu, possible: %llu)\n", + state->period, s2.period, last->period); - if (ops->request) { - err = ops->request(chip, pwm); - if (err) { - module_put(chip->owner); - return err; - } - } + if (state->enabled && state->period < s2.period) + dev_warn(pwmchip_parent(chip), + ".apply is supposed to round down period (requested: %llu, applied: %llu)\n", + state->period, s2.period); - if (ops->get_state) { - /* - * Zero-initialize state because most drivers are unaware of - * .usage_power. The other members of state are supposed to be - * set by lowlevel drivers. We still initialize the whole - * structure for simplicity even though this might paper over - * faulty implementations of .get_state(). - */ - struct pwm_state state = { 0, }; + if (state->enabled && + last->polarity == state->polarity && + last->period == s2.period && + last->duty_cycle > s2.duty_cycle && + last->duty_cycle <= state->duty_cycle) + dev_warn(pwmchip_parent(chip), + ".apply didn't pick the best available duty cycle (requested: %llu/%llu, applied: %llu/%llu, possible: %llu/%llu)\n", + state->duty_cycle, state->period, + s2.duty_cycle, s2.period, + last->duty_cycle, last->period); - err = ops->get_state(chip, pwm, &state); - trace_pwm_get(pwm, &state, err); + if (state->enabled && state->duty_cycle < s2.duty_cycle) + dev_warn(pwmchip_parent(chip), + ".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n", + state->duty_cycle, state->period, + s2.duty_cycle, s2.period); - if (!err) - pwm->state = state; + if (!state->enabled && s2.enabled && s2.duty_cycle > 0) + dev_warn(pwmchip_parent(chip), + "requested disabled, but yielded enabled with duty > 0\n"); - if (IS_ENABLED(CONFIG_PWM_DEBUG)) - pwm->last = pwm->state; + /* reapply the state that the driver reported being configured. */ + err = chip->ops->apply(chip, pwm, &s1); + trace_pwm_apply(pwm, &s1, err); + if (err) { + *last = s1; + dev_err(pwmchip_parent(chip), "failed to reapply current setting\n"); + return; } - set_bit(PWMF_REQUESTED, &pwm->flags); - pwm->label = label; + *last = (struct pwm_state){ 0 }; + err = chip->ops->get_state(chip, pwm, last); + trace_pwm_get(pwm, last, err); + if (err) + return; - return 0; + /* reapplication of the current state should give an exact match */ + if (s1.enabled != last->enabled || + s1.polarity != last->polarity || + (s1.enabled && s1.period != last->period) || + (s1.enabled && s1.duty_cycle != last->duty_cycle)) { + dev_err(pwmchip_parent(chip), + ".apply is not idempotent (ena=%d pol=%d %llu/%llu) -> (ena=%d pol=%d %llu/%llu)\n", + s1.enabled, s1.polarity, s1.duty_cycle, s1.period, + last->enabled, last->polarity, last->duty_cycle, + last->period); + } } -struct pwm_device * -of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) +/** + * __pwm_apply() - atomically apply a new state to a PWM device + * @pwm: PWM device + * @state: new state to apply + */ +static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) { - struct pwm_device *pwm; + struct pwm_chip *chip; + int err; - if (chip->of_pwm_n_cells < 2) - return ERR_PTR(-EINVAL); + if (!pwm || !state || !state->period || + state->duty_cycle > state->period) + return -EINVAL; - /* flags in the third cell are optional */ - if (args->args_count < 2) - return ERR_PTR(-EINVAL); + chip = pwm->chip; - if (args->args[0] >= chip->npwm) - return ERR_PTR(-EINVAL); + if (state->period == pwm->state.period && + state->duty_cycle == pwm->state.duty_cycle && + state->polarity == pwm->state.polarity && + state->enabled == pwm->state.enabled && + state->usage_power == pwm->state.usage_power) + return 0; - pwm = pwm_request_from_chip(chip, args->args[0], NULL); - if (IS_ERR(pwm)) - return pwm; + err = chip->ops->apply(chip, pwm, state); + trace_pwm_apply(pwm, state, err); + if (err) + return err; - pwm->args.period = args->args[1]; - pwm->args.polarity = PWM_POLARITY_NORMAL; + pwm->state = *state; - if (chip->of_pwm_n_cells >= 3) { - if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) - pwm->args.polarity = PWM_POLARITY_INVERSED; - } + /* + * only do this after pwm->state was applied as some + * implementations of .get_state depend on this + */ + pwm_apply_debug(pwm, state); - return pwm; + return 0; } -EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); -struct pwm_device * -of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) +/** + * pwm_apply_might_sleep() - atomically apply a new state to a PWM device + * Cannot be used in atomic context. + * @pwm: PWM device + * @state: new state to apply + */ +int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) { - struct pwm_device *pwm; - - if (chip->of_pwm_n_cells < 1) - return ERR_PTR(-EINVAL); + int err; - /* validate that one cell is specified, optionally with flags */ - if (args->args_count != 1 && args->args_count != 2) - return ERR_PTR(-EINVAL); + /* + * Some lowlevel driver's implementations of .apply() make use of + * mutexes, also with some drivers only returning when the new + * configuration is active calling pwm_apply_might_sleep() from atomic context + * is a bad idea. So make it explicit that calling this function might + * sleep. + */ + might_sleep(); - pwm = pwm_request_from_chip(chip, 0, NULL); - if (IS_ERR(pwm)) - return pwm; + if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) { + /* + * Catch any drivers that have been marked as atomic but + * that will sleep anyway. + */ + non_block_start(); + err = __pwm_apply(pwm, state); + non_block_end(); + } else { + err = __pwm_apply(pwm, state); + } - pwm->args.period = args->args[0]; - pwm->args.polarity = PWM_POLARITY_NORMAL; + return err; +} +EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); - if (args->args_count == 2 && args->args[1] & PWM_POLARITY_INVERTED) - pwm->args.polarity = PWM_POLARITY_INVERSED; +/** + * pwm_apply_atomic() - apply a new state to a PWM device from atomic context + * Not all PWM devices support this function, check with pwm_might_sleep(). + * @pwm: PWM device + * @state: new state to apply + */ +int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state) +{ + WARN_ONCE(!pwm->chip->atomic, + "sleeping PWM driver used in atomic context\n"); - return pwm; + return __pwm_apply(pwm, state); } -EXPORT_SYMBOL_GPL(of_pwm_single_xlate); +EXPORT_SYMBOL_GPL(pwm_apply_atomic); -static void of_pwmchip_add(struct pwm_chip *chip) +/** + * pwm_adjust_config() - adjust the current PWM config to the PWM arguments + * @pwm: PWM device + * + * This function will adjust the PWM config to the PWM arguments provided + * by the DT or PWM lookup table. This is particularly useful to adapt + * the bootloader config to the Linux one. + */ +int pwm_adjust_config(struct pwm_device *pwm) { - if (!chip->dev || !chip->dev->of_node) - return; + struct pwm_state state; + struct pwm_args pargs; - if (!chip->of_xlate) { - u32 pwm_cells; + pwm_get_args(pwm, &pargs); + pwm_get_state(pwm, &state); - if (of_property_read_u32(chip->dev->of_node, "#pwm-cells", - &pwm_cells)) - pwm_cells = 2; + /* + * If the current period is zero it means that either the PWM driver + * does not support initial state retrieval or the PWM has not yet + * been configured. + * + * In either case, we setup the new period and polarity, and assign a + * duty cycle of 0. + */ + if (!state.period) { + state.duty_cycle = 0; + state.period = pargs.period; + state.polarity = pargs.polarity; - chip->of_xlate = of_pwm_xlate_with_flags; - chip->of_pwm_n_cells = pwm_cells; + return pwm_apply_might_sleep(pwm, &state); } - of_node_get(chip->dev->of_node); -} - -static void of_pwmchip_remove(struct pwm_chip *chip) -{ - if (chip->dev) - of_node_put(chip->dev->of_node); -} - -static bool pwm_ops_check(const struct pwm_chip *chip) -{ - const struct pwm_ops *ops = chip->ops; - - if (!ops->apply) - return false; + /* + * Adjust the PWM duty cycle/period based on the period value provided + * in PWM args. + */ + if (pargs.period != state.period) { + u64 dutycycle = (u64)state.duty_cycle * pargs.period; - if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state) - dev_warn(chip->dev, - "Please implement the .get_state() callback\n"); + do_div(dutycycle, state.period); + state.duty_cycle = dutycycle; + state.period = pargs.period; + } - return true; + /* + * If the polarity changed, we should also change the duty cycle. + */ + if (pargs.polarity != state.polarity) { + state.polarity = pargs.polarity; + state.duty_cycle = state.period - state.duty_cycle; + } + + return pwm_apply_might_sleep(pwm, &state); } +EXPORT_SYMBOL_GPL(pwm_adjust_config); /** - * __pwmchip_add() - register a new PWM chip - * @chip: the PWM chip to add - * @owner: reference to the module providing the chip. - * - * Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the - * pwmchip_add wrapper to do this right. + * pwm_capture() - capture and report a PWM signal + * @pwm: PWM device + * @result: structure to fill with capture result + * @timeout: time to wait, in milliseconds, before giving up on capture * * Returns: 0 on success or a negative error code on failure. */ -int __pwmchip_add(struct pwm_chip *chip, struct module *owner) +int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, + unsigned long timeout) { - unsigned int i; - int ret; + int err; - if (!chip || !chip->dev || !chip->ops || !chip->npwm) + if (!pwm || !pwm->chip->ops) return -EINVAL; - if (!pwm_ops_check(chip)) - return -EINVAL; + if (!pwm->chip->ops->capture) + return -ENOSYS; - chip->owner = owner; + mutex_lock(&pwm_lock); + err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout); + mutex_unlock(&pwm_lock); - chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL); - if (!chip->pwms) - return -ENOMEM; + return err; +} +EXPORT_SYMBOL_GPL(pwm_capture); - mutex_lock(&pwm_lock); +static struct pwm_chip *pwmchip_find_by_name(const char *name) +{ + struct pwm_chip *chip; + unsigned long id, tmp; - ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); - if (ret < 0) { - mutex_unlock(&pwm_lock); - kfree(chip->pwms); - return ret; - } + if (!name) + return NULL; - chip->id = ret; + mutex_lock(&pwm_lock); - for (i = 0; i < chip->npwm; i++) { - struct pwm_device *pwm = &chip->pwms[i]; + idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) { + const char *chip_name = dev_name(pwmchip_parent(chip)); - pwm->chip = chip; - pwm->hwpwm = i; + if (chip_name && strcmp(chip_name, name) == 0) { + mutex_unlock(&pwm_lock); + return chip; + } } mutex_unlock(&pwm_lock); - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_add(chip); - - pwmchip_sysfs_export(chip); - - return 0; + return NULL; } -EXPORT_SYMBOL_GPL(__pwmchip_add); -/** - * pwmchip_remove() - remove a PWM chip - * @chip: the PWM chip to remove - * - * Removes a PWM chip. - */ -void pwmchip_remove(struct pwm_chip *chip) +static int pwm_device_request(struct pwm_device *pwm, const char *label) { - pwmchip_sysfs_unexport(chip); - - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_remove(chip); + int err; + struct pwm_chip *chip = pwm->chip; + const struct pwm_ops *ops = chip->ops; - mutex_lock(&pwm_lock); + if (test_bit(PWMF_REQUESTED, &pwm->flags)) + return -EBUSY; - idr_remove(&pwm_chips, chip->id); + if (!try_module_get(chip->owner)) + return -ENODEV; - mutex_unlock(&pwm_lock); + if (ops->request) { + err = ops->request(chip, pwm); + if (err) { + module_put(chip->owner); + return err; + } + } - kfree(chip->pwms); -} -EXPORT_SYMBOL_GPL(pwmchip_remove); + if (ops->get_state) { + /* + * Zero-initialize state because most drivers are unaware of + * .usage_power. The other members of state are supposed to be + * set by lowlevel drivers. We still initialize the whole + * structure for simplicity even though this might paper over + * faulty implementations of .get_state(). + */ + struct pwm_state state = { 0, }; -static void devm_pwmchip_remove(void *data) -{ - struct pwm_chip *chip = data; + err = ops->get_state(chip, pwm, &state); + trace_pwm_get(pwm, &state, err); - pwmchip_remove(chip); -} + if (!err) + pwm->state = state; -int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner) -{ - int ret; + if (IS_ENABLED(CONFIG_PWM_DEBUG)) + pwm->last = pwm->state; + } - ret = __pwmchip_add(chip, owner); - if (ret) - return ret; + set_bit(PWMF_REQUESTED, &pwm->flags); + pwm->label = label; - return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); + return 0; } -EXPORT_SYMBOL_GPL(__devm_pwmchip_add); /** * pwm_request_from_chip() - request a PWM device relative to a PWM chip @@ -328,301 +409,179 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, } EXPORT_SYMBOL_GPL(pwm_request_from_chip); -static void pwm_apply_debug(struct pwm_device *pwm, - const struct pwm_state *state) -{ - struct pwm_state *last = &pwm->last; - struct pwm_chip *chip = pwm->chip; - struct pwm_state s1 = { 0 }, s2 = { 0 }; - int err; - - if (!IS_ENABLED(CONFIG_PWM_DEBUG)) - return; - - /* No reasonable diagnosis possible without .get_state() */ - if (!chip->ops->get_state) - return; - - /* - * *state was just applied. Read out the hardware state and do some - * checks. - */ - - err = chip->ops->get_state(chip, pwm, &s1); - trace_pwm_get(pwm, &s1, err); - if (err) - /* If that failed there isn't much to debug */ - return; - - /* - * The lowlevel driver either ignored .polarity (which is a bug) or as - * best effort inverted .polarity and fixed .duty_cycle respectively. - * Undo this inversion and fixup for further tests. - */ - if (s1.enabled && s1.polarity != state->polarity) { - s2.polarity = state->polarity; - s2.duty_cycle = s1.period - s1.duty_cycle; - s2.period = s1.period; - s2.enabled = s1.enabled; - } else { - s2 = s1; - } - - if (s2.polarity != state->polarity && - state->duty_cycle < state->period) - dev_warn(chip->dev, ".apply ignored .polarity\n"); - - if (state->enabled && - last->polarity == state->polarity && - last->period > s2.period && - last->period <= state->period) - dev_warn(chip->dev, - ".apply didn't pick the best available period (requested: %llu, applied: %llu, possible: %llu)\n", - state->period, s2.period, last->period); - - if (state->enabled && state->period < s2.period) - dev_warn(chip->dev, - ".apply is supposed to round down period (requested: %llu, applied: %llu)\n", - state->period, s2.period); - - if (state->enabled && - last->polarity == state->polarity && - last->period == s2.period && - last->duty_cycle > s2.duty_cycle && - last->duty_cycle <= state->duty_cycle) - dev_warn(chip->dev, - ".apply didn't pick the best available duty cycle (requested: %llu/%llu, applied: %llu/%llu, possible: %llu/%llu)\n", - state->duty_cycle, state->period, - s2.duty_cycle, s2.period, - last->duty_cycle, last->period); - - if (state->enabled && state->duty_cycle < s2.duty_cycle) - dev_warn(chip->dev, - ".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n", - state->duty_cycle, state->period, - s2.duty_cycle, s2.period); - - if (!state->enabled && s2.enabled && s2.duty_cycle > 0) - dev_warn(chip->dev, - "requested disabled, but yielded enabled with duty > 0\n"); - - /* reapply the state that the driver reported being configured. */ - err = chip->ops->apply(chip, pwm, &s1); - trace_pwm_apply(pwm, &s1, err); - if (err) { - *last = s1; - dev_err(chip->dev, "failed to reapply current setting\n"); - return; - } - - *last = (struct pwm_state){ 0 }; - err = chip->ops->get_state(chip, pwm, last); - trace_pwm_get(pwm, last, err); - if (err) - return; - - /* reapplication of the current state should give an exact match */ - if (s1.enabled != last->enabled || - s1.polarity != last->polarity || - (s1.enabled && s1.period != last->period) || - (s1.enabled && s1.duty_cycle != last->duty_cycle)) { - dev_err(chip->dev, - ".apply is not idempotent (ena=%d pol=%d %llu/%llu) -> (ena=%d pol=%d %llu/%llu)\n", - s1.enabled, s1.polarity, s1.duty_cycle, s1.period, - last->enabled, last->polarity, last->duty_cycle, - last->period); - } -} -/** - * __pwm_apply() - atomically apply a new state to a PWM device - * @pwm: PWM device - * @state: new state to apply - */ -static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) +struct pwm_device * +of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) { - struct pwm_chip *chip; - int err; + struct pwm_device *pwm; - if (!pwm || !state || !state->period || - state->duty_cycle > state->period) - return -EINVAL; + /* period in the second cell and flags in the third cell are optional */ + if (args->args_count < 1) + return ERR_PTR(-EINVAL); - chip = pwm->chip; + pwm = pwm_request_from_chip(chip, args->args[0], NULL); + if (IS_ERR(pwm)) + return pwm; - if (state->period == pwm->state.period && - state->duty_cycle == pwm->state.duty_cycle && - state->polarity == pwm->state.polarity && - state->enabled == pwm->state.enabled && - state->usage_power == pwm->state.usage_power) - return 0; + if (args->args_count > 1) + pwm->args.period = args->args[1]; - err = chip->ops->apply(chip, pwm, state); - trace_pwm_apply(pwm, state, err); - if (err) - return err; + pwm->args.polarity = PWM_POLARITY_NORMAL; + if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) + pwm->args.polarity = PWM_POLARITY_INVERSED; - pwm->state = *state; + return pwm; +} +EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); - /* - * only do this after pwm->state was applied as some - * implementations of .get_state depend on this - */ - pwm_apply_debug(pwm, state); +struct pwm_device * +of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) +{ + struct pwm_device *pwm; - return 0; + pwm = pwm_request_from_chip(chip, 0, NULL); + if (IS_ERR(pwm)) + return pwm; + + if (args->args_count > 0) + pwm->args.period = args->args[0]; + + pwm->args.polarity = PWM_POLARITY_NORMAL; + if (args->args_count > 1 && args->args[1] & PWM_POLARITY_INVERTED) + pwm->args.polarity = PWM_POLARITY_INVERSED; + + return pwm; } +EXPORT_SYMBOL_GPL(of_pwm_single_xlate); -/** - * pwm_apply_might_sleep() - atomically apply a new state to a PWM device - * Cannot be used in atomic context. - * @pwm: PWM device - * @state: new state to apply - */ -int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) +static void of_pwmchip_add(struct pwm_chip *chip) { - int err; + if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node) + return; - /* - * Some lowlevel driver's implementations of .apply() make use of - * mutexes, also with some drivers only returning when the new - * configuration is active calling pwm_apply_might_sleep() from atomic context - * is a bad idea. So make it explicit that calling this function might - * sleep. - */ - might_sleep(); + if (!chip->of_xlate) + chip->of_xlate = of_pwm_xlate_with_flags; - if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) { - /* - * Catch any drivers that have been marked as atomic but - * that will sleep anyway. - */ - non_block_start(); - err = __pwm_apply(pwm, state); - non_block_end(); - } else { - err = __pwm_apply(pwm, state); - } + of_node_get(pwmchip_parent(chip)->of_node); +} - return err; +static void of_pwmchip_remove(struct pwm_chip *chip) +{ + if (pwmchip_parent(chip)) + of_node_put(pwmchip_parent(chip)->of_node); } -EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); -/** - * pwm_apply_atomic() - apply a new state to a PWM device from atomic context - * Not all PWM devices support this function, check with pwm_might_sleep(). - * @pwm: PWM device - * @state: new state to apply - */ -int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state) +static bool pwm_ops_check(const struct pwm_chip *chip) { - WARN_ONCE(!pwm->chip->atomic, - "sleeping PWM driver used in atomic context\n"); + const struct pwm_ops *ops = chip->ops; - return __pwm_apply(pwm, state); + if (!ops->apply) + return false; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state) + dev_warn(pwmchip_parent(chip), + "Please implement the .get_state() callback\n"); + + return true; } -EXPORT_SYMBOL_GPL(pwm_apply_atomic); /** - * pwm_capture() - capture and report a PWM signal - * @pwm: PWM device - * @result: structure to fill with capture result - * @timeout: time to wait, in milliseconds, before giving up on capture + * __pwmchip_add() - register a new PWM chip + * @chip: the PWM chip to add + * @owner: reference to the module providing the chip. + * + * Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the + * pwmchip_add wrapper to do this right. * * Returns: 0 on success or a negative error code on failure. */ -int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, - unsigned long timeout) +int __pwmchip_add(struct pwm_chip *chip, struct module *owner) { - int err; + unsigned int i; + int ret; - if (!pwm || !pwm->chip->ops) + if (!chip || !pwmchip_parent(chip) || !chip->ops || !chip->npwm) return -EINVAL; - if (!pwm->chip->ops->capture) - return -ENOSYS; + if (!pwm_ops_check(chip)) + return -EINVAL; + + chip->owner = owner; + + chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL); + if (!chip->pwms) + return -ENOMEM; mutex_lock(&pwm_lock); - err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout); + + ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); + if (ret < 0) { + mutex_unlock(&pwm_lock); + kfree(chip->pwms); + return ret; + } + + chip->id = ret; + + for (i = 0; i < chip->npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + + pwm->chip = chip; + pwm->hwpwm = i; + } + mutex_unlock(&pwm_lock); - return err; + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_add(chip); + + pwmchip_sysfs_export(chip); + + return 0; } -EXPORT_SYMBOL_GPL(pwm_capture); +EXPORT_SYMBOL_GPL(__pwmchip_add); /** - * pwm_adjust_config() - adjust the current PWM config to the PWM arguments - * @pwm: PWM device + * pwmchip_remove() - remove a PWM chip + * @chip: the PWM chip to remove * - * This function will adjust the PWM config to the PWM arguments provided - * by the DT or PWM lookup table. This is particularly useful to adapt - * the bootloader config to the Linux one. + * Removes a PWM chip. */ -int pwm_adjust_config(struct pwm_device *pwm) +void pwmchip_remove(struct pwm_chip *chip) { - struct pwm_state state; - struct pwm_args pargs; - - pwm_get_args(pwm, &pargs); - pwm_get_state(pwm, &state); - - /* - * If the current period is zero it means that either the PWM driver - * does not support initial state retrieval or the PWM has not yet - * been configured. - * - * In either case, we setup the new period and polarity, and assign a - * duty cycle of 0. - */ - if (!state.period) { - state.duty_cycle = 0; - state.period = pargs.period; - state.polarity = pargs.polarity; + pwmchip_sysfs_unexport(chip); - return pwm_apply_might_sleep(pwm, &state); - } + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); - /* - * Adjust the PWM duty cycle/period based on the period value provided - * in PWM args. - */ - if (pargs.period != state.period) { - u64 dutycycle = (u64)state.duty_cycle * pargs.period; + mutex_lock(&pwm_lock); - do_div(dutycycle, state.period); - state.duty_cycle = dutycycle; - state.period = pargs.period; - } + idr_remove(&pwm_chips, chip->id); - /* - * If the polarity changed, we should also change the duty cycle. - */ - if (pargs.polarity != state.polarity) { - state.polarity = pargs.polarity; - state.duty_cycle = state.period - state.duty_cycle; - } + mutex_unlock(&pwm_lock); - return pwm_apply_might_sleep(pwm, &state); + kfree(chip->pwms); } -EXPORT_SYMBOL_GPL(pwm_adjust_config); +EXPORT_SYMBOL_GPL(pwmchip_remove); -static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode) +static void devm_pwmchip_remove(void *data) { - struct pwm_chip *chip; - unsigned long id, tmp; + struct pwm_chip *chip = data; - mutex_lock(&pwm_lock); + pwmchip_remove(chip); +} - idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) - if (chip->dev && device_match_fwnode(chip->dev, fwnode)) { - mutex_unlock(&pwm_lock); - return chip; - } +int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner) +{ + int ret; - mutex_unlock(&pwm_lock); + ret = __pwmchip_add(chip, owner); + if (ret) + return ret; - return ERR_PTR(-EPROBE_DEFER); + return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); } +EXPORT_SYMBOL_GPL(__devm_pwmchip_add); static struct device_link *pwm_device_link_add(struct device *dev, struct pwm_device *pwm) @@ -635,21 +594,39 @@ static struct device_link *pwm_device_link_add(struct device *dev, * impact the PM sequence ordering: the PWM supplier may get * suspended before the consumer. */ - dev_warn(pwm->chip->dev, + dev_warn(pwmchip_parent(pwm->chip), "No consumer device specified to create a link to\n"); return NULL; } - dl = device_link_add(dev, pwm->chip->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + dl = device_link_add(dev, pwmchip_parent(pwm->chip), DL_FLAG_AUTOREMOVE_CONSUMER); if (!dl) { dev_err(dev, "failed to create device link to %s\n", - dev_name(pwm->chip->dev)); + dev_name(pwmchip_parent(pwm->chip))); return ERR_PTR(-EINVAL); } return dl; } +static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode) +{ + struct pwm_chip *chip; + unsigned long id, tmp; + + mutex_lock(&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); + return chip; + } + + mutex_unlock(&pwm_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + /** * of_pwm_get() - request a PWM via the PWM framework * @dev: device for PWM consumer @@ -784,6 +761,9 @@ static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode) return pwm; } +static DEFINE_MUTEX(pwm_lookup_lock); +static LIST_HEAD(pwm_lookup_list); + /** * pwm_add_table() - register PWM device consumers * @table: array of consumers to register @@ -1105,8 +1085,8 @@ static int pwm_seq_show(struct seq_file *s, void *v) seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n", (char *)s->private, chip->id, - chip->dev->bus ? chip->dev->bus->name : "no-bus", - dev_name(chip->dev), chip->npwm, + pwmchip_parent(chip)->bus ? pwmchip_parent(chip)->bus->name : "no-bus", + dev_name(pwmchip_parent(chip)), chip->npwm, (chip->npwm != 1) ? "s" : ""); pwm_dbg_show(chip, s); diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c index 42179b3f7e..06562d4bb9 100644 --- a/drivers/pwm/pwm-clps711x.c +++ b/drivers/pwm/pwm-clps711x.c @@ -103,7 +103,6 @@ static int clps711x_pwm_probe(struct platform_device *pdev) priv->chip.dev = &pdev->dev; priv->chip.npwm = 2; priv->chip.of_xlate = clps711x_pwm_xlate; - priv->chip.of_pwm_n_cells = 1; spin_lock_init(&priv->lock); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 5fe303b865..339cedf3a7 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -279,7 +279,6 @@ static int cros_ec_pwm_probe(struct platform_device *pdev) chip->dev = dev; chip->ops = &cros_ec_pwm_ops; chip->of_xlate = cros_ec_pwm_xlate; - chip->of_pwm_n_cells = 1; if (ec_pwm->use_pwm_type) { chip->npwm = CROS_EC_PWM_DT_COUNT; diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 2971bbf3b5..52ac3277f4 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -122,7 +122,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct meson_pwm *meson = to_meson_pwm(chip); struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; - struct device *dev = chip->dev; + struct device *dev = pwmchip_parent(chip); int err; err = clk_prepare_enable(channel->clk); @@ -143,12 +143,13 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(channel->clk); } -static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, +static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { + struct meson_pwm *meson = to_meson_pwm(chip); struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; unsigned int cnt, duty_cnt; - unsigned long fin_freq; + long fin_freq; u64 duty, period, freq; duty = state->duty_cycle; @@ -168,20 +169,21 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, freq = ULONG_MAX; fin_freq = clk_round_rate(channel->clk, freq); - if (fin_freq == 0) { - dev_err(meson->chip.dev, "invalid source clock frequency\n"); - return -EINVAL; + if (fin_freq <= 0) { + dev_err(pwmchip_parent(chip), + "invalid source clock frequency %llu\n", freq); + return fin_freq ? fin_freq : -EINVAL; } - dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); + dev_dbg(pwmchip_parent(chip), "fin_freq: %ld Hz\n", fin_freq); - cnt = div_u64(fin_freq * period, NSEC_PER_SEC); + cnt = mul_u64_u64_div_u64(fin_freq, period, NSEC_PER_SEC); if (cnt > 0xffff) { - dev_err(meson->chip.dev, "unable to get period cnt\n"); + dev_err(pwmchip_parent(chip), "unable to get period cnt\n"); return -EINVAL; } - dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt); + dev_dbg(pwmchip_parent(chip), "period=%llu cnt=%u\n", period, cnt); if (duty == period) { channel->hi = cnt; @@ -190,9 +192,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, channel->hi = 0; channel->lo = cnt; } else { - duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC); + duty_cnt = mul_u64_u64_div_u64(fin_freq, duty, NSEC_PER_SEC); - dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt); + dev_dbg(pwmchip_parent(chip), "duty=%llu duty_cnt=%u\n", duty, duty_cnt); channel->hi = duty_cnt; channel->lo = cnt - duty_cnt; @@ -203,8 +205,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, return 0; } -static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm) +static void meson_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { + struct meson_pwm *meson = to_meson_pwm(chip); struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm]; struct meson_pwm_channel_data *channel_data; unsigned long flags; @@ -215,7 +218,7 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm) err = clk_set_rate(channel->clk, channel->rate); if (err) - dev_err(meson->chip.dev, "setting clock rate failed\n"); + dev_err(pwmchip_parent(chip), "setting clock rate failed\n"); spin_lock_irqsave(&meson->lock, flags); @@ -230,8 +233,9 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm) spin_unlock_irqrestore(&meson->lock, flags); } -static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm) +static void meson_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { + struct meson_pwm *meson = to_meson_pwm(chip); unsigned long flags; u32 value; @@ -269,16 +273,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, channel->hi = ~0; channel->lo = 0; - meson_pwm_enable(meson, pwm); + meson_pwm_enable(chip, pwm); } else { - meson_pwm_disable(meson, pwm); + meson_pwm_disable(chip, pwm); } } else { - err = meson_pwm_calc(meson, pwm, state); + err = meson_pwm_calc(chip, pwm, state); if (err < 0) return err; - meson_pwm_enable(meson, pwm); + meson_pwm_enable(chip, pwm); } return 0; @@ -432,10 +436,11 @@ static const struct of_device_id meson_pwm_matches[] = { }; MODULE_DEVICE_TABLE(of, meson_pwm_matches); -static int meson_pwm_init_channels(struct meson_pwm *meson) +static int meson_pwm_init_channels(struct pwm_chip *chip) { + struct meson_pwm *meson = to_meson_pwm(chip); struct clk_parent_data mux_parent_data[MESON_MAX_MUX_PARENTS] = {}; - struct device *dev = meson->chip.dev; + struct device *dev = pwmchip_parent(chip); unsigned int i; char name[255]; int err; @@ -445,7 +450,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson) mux_parent_data[i].name = meson->data->parent_names[i]; } - for (i = 0; i < meson->chip.npwm; i++) { + for (i = 0; i < chip->npwm; i++) { struct meson_pwm_channel *channel = &meson->channels[i]; struct clk_parent_data div_parent = {}, gate_parent = {}; struct clk_init_data init = {}; @@ -543,7 +548,7 @@ static int meson_pwm_probe(struct platform_device *pdev) meson->data = of_device_get_match_data(&pdev->dev); - err = meson_pwm_init_channels(meson); + err = meson_pwm_init_channels(&meson->chip); if (err < 0) return err; diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 76685f926c..61b74fa1d3 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -180,10 +180,8 @@ static int pwm_probe(struct platform_device *pdev) pc->chip.ops = &pxa_pwm_ops; pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; - if (IS_ENABLED(CONFIG_OF)) { + if (IS_ENABLED(CONFIG_OF)) pc->chip.of_xlate = of_pwm_single_xlate; - pc->chip.of_pwm_n_cells = 1; - } pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio_base)) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 69b1113c6b..f3df7b1895 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -570,6 +570,7 @@ static int sti_pwm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sti_pwm_compat_data *cdata; + struct pwm_chip *chip; struct sti_pwm_chip *pc; unsigned int i; int irq, ret; @@ -577,6 +578,7 @@ static int sti_pwm_probe(struct platform_device *pdev) pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); if (!pc) return -ENOMEM; + chip = &pc->chip; cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL); if (!cdata) @@ -622,40 +624,28 @@ static int sti_pwm_probe(struct platform_device *pdev) return ret; if (cdata->pwm_num_devs) { - pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); + pc->pwm_clk = devm_clk_get_prepared(dev, "pwm"); if (IS_ERR(pc->pwm_clk)) { dev_err(dev, "failed to get PWM clock\n"); return PTR_ERR(pc->pwm_clk); } - - ret = clk_prepare(pc->pwm_clk); - if (ret) { - dev_err(dev, "failed to prepare clock\n"); - return ret; - } } if (cdata->cpt_num_devs) { - pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); + pc->cpt_clk = devm_clk_get_prepared(dev, "capture"); if (IS_ERR(pc->cpt_clk)) { dev_err(dev, "failed to get PWM capture clock\n"); return PTR_ERR(pc->cpt_clk); } - ret = clk_prepare(pc->cpt_clk); - if (ret) { - dev_err(dev, "failed to prepare clock\n"); - return ret; - } - cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL); if (!cdata->ddata) return -ENOMEM; } - pc->chip.dev = dev; - pc->chip.ops = &sti_pwm_ops; - pc->chip.npwm = max(cdata->pwm_num_devs, cdata->cpt_num_devs); + chip->dev = dev; + chip->ops = &sti_pwm_ops; + chip->npwm = max(cdata->pwm_num_devs, cdata->cpt_num_devs); for (i = 0; i < cdata->cpt_num_devs; i++) { struct sti_cpt_ddata *ddata = &cdata->ddata[i]; @@ -664,26 +654,7 @@ static int sti_pwm_probe(struct platform_device *pdev) mutex_init(&ddata->lock); } - ret = pwmchip_add(&pc->chip); - if (ret < 0) { - clk_unprepare(pc->pwm_clk); - clk_unprepare(pc->cpt_clk); - return ret; - } - - platform_set_drvdata(pdev, pc); - - return 0; -} - -static void sti_pwm_remove(struct platform_device *pdev) -{ - struct sti_pwm_chip *pc = platform_get_drvdata(pdev); - - pwmchip_remove(&pc->chip); - - clk_unprepare(pc->pwm_clk); - clk_unprepare(pc->cpt_clk); + return devm_pwmchip_add(dev, chip); } static const struct of_device_id sti_pwm_of_match[] = { @@ -698,7 +669,6 @@ static struct platform_driver sti_pwm_driver = { .of_match_table = sti_pwm_of_match, }, .probe = sti_pwm_probe, - .remove_new = sti_pwm_remove, }; module_platform_driver(sti_pwm_driver); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 1698609d91..3f434a771f 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -509,10 +509,10 @@ void pwmchip_sysfs_export(struct pwm_chip *chip) * If device_create() fails the pwm_chip is still usable by * the kernel it's just not exported. */ - parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip, + parent = device_create(&pwm_class, pwmchip_parent(chip), MKDEV(0, 0), chip, "pwmchip%d", chip->id); if (IS_ERR(parent)) { - dev_warn(chip->dev, + dev_warn(pwmchip_parent(chip), "device_create failed for pwm_chip sysfs export\n"); } } -- cgit v1.2.3