diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-25 19:40:15 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-25 19:40:15 +0200 |
commit | ecc5fbd5ef472a4c659dc56a5739b3f041c0530c (patch) | |
tree | eec1c3ddd6082e6391d7d27ae78d813a8f6c216c /drivers | |
parent | Merge git://www.linux-watchdog.org/linux-watchdog (diff) | |
parent | Merge branch 'for-4.7/pwm-atomic' into for-next (diff) | |
download | linux-ecc5fbd5ef472a4c659dc56a5739b3f041c0530c.tar.xz linux-ecc5fbd5ef472a4c659dc56a5739b3f041c0530c.zip |
Merge tag 'pwm/for-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding:
"This set of changes introduces an atomic API to the PWM subsystem.
This is influenced by the DRM atomic API that was introduced a while
back, though it is obviously a lot simpler. The fundamental idea
remains the same, though: drivers provide a single callback to
implement the atomic configuration of a PWM channel.
As a side-effect the PWM subsystem gains the ability for initial state
retrieval, so that the logical state mirrors that of the hardware.
Many use-cases don't care about this, but for others it is essential.
These new features require changes in all users, which these patches
take care of. The core is transitioned to use the atomic callback if
available and provides a fallback mechanism for other drivers.
Changes to transition users and drivers to the atomic API are
postponed to v4.8"
* tag 'pwm/for-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (30 commits)
pwm: Add information about polarity, duty cycle and period to debugfs
pwm: Switch to the atomic API
pwm: Update documentation
pwm: Add core infrastructure to allow atomic updates
pwm: Add hardware readout infrastructure
pwm: Move the enabled/disabled info into pwm_state
pwm: Introduce the pwm_state concept
pwm: Keep PWM state in sync with hardware state
ARM: Explicitly apply PWM config extracted from pwm_args
drm: i915: Explicitly apply PWM config extracted from pwm_args
input: misc: pwm-beeper: Explicitly apply PWM config extracted from pwm_args
input: misc: max8997: Explicitly apply PWM config extracted from pwm_args
backlight: lm3630a: explicitly apply PWM config extracted from pwm_args
backlight: lp855x: Explicitly apply PWM config extracted from pwm_args
backlight: lp8788: Explicitly apply PWM config extracted from pwm_args
backlight: pwm_bl: Use pwm_get_args() where appropriate
fbdev: ssd1307fb: Use pwm_get_args() where appropriate
regulator: pwm: Use pwm_get_args() where appropriate
leds: pwm: Use pwm_get_args() where appropriate
input: misc: max77693: Use pwm_get_args() where appropriate
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk-pwm.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 6 | ||||
-rw-r--r-- | drivers/hwmon/pwm-fan.c | 26 | ||||
-rw-r--r-- | drivers/input/misc/max77693-haptic.c | 17 | ||||
-rw-r--r-- | drivers/input/misc/max8997_haptic.c | 6 | ||||
-rw-r--r-- | drivers/input/misc/pwm-beeper.c | 6 | ||||
-rw-r--r-- | drivers/leds/leds-pwm.c | 11 | ||||
-rw-r--r-- | drivers/pwm/core.c | 224 | ||||
-rw-r--r-- | drivers/pwm/pwm-crc.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpc18xx-sct.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-omap-dmtimer.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-rcar.c | 2 | ||||
-rw-r--r-- | drivers/pwm/pwm-sun4i.c | 3 | ||||
-rw-r--r-- | drivers/pwm/sysfs.c | 70 | ||||
-rw-r--r-- | drivers/video/backlight/lm3630a_bl.c | 9 | ||||
-rw-r--r-- | drivers/video/backlight/lp855x_bl.c | 6 | ||||
-rw-r--r-- | drivers/video/backlight/lp8788_bl.c | 6 | ||||
-rw-r--r-- | drivers/video/backlight/pwm_bl.c | 14 | ||||
-rw-r--r-- | drivers/video/fbdev/ssd1307fb.c | 11 |
19 files changed, 312 insertions, 128 deletions
diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 883045814dac..1630a1f085f7 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -59,6 +59,7 @@ static int clk_pwm_probe(struct platform_device *pdev) struct clk_init_data init; struct clk_pwm *clk_pwm; struct pwm_device *pwm; + struct pwm_args pargs; const char *clk_name; struct clk *clk; int ret; @@ -71,22 +72,28 @@ static int clk_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm)) return PTR_ERR(pwm); - if (!pwm->period) { + pwm_get_args(pwm, &pargs); + if (!pargs.period) { dev_err(&pdev->dev, "invalid PWM period\n"); return -EINVAL; } if (of_property_read_u32(node, "clock-frequency", &clk_pwm->fixed_rate)) - clk_pwm->fixed_rate = NSEC_PER_SEC / pwm->period; + clk_pwm->fixed_rate = NSEC_PER_SEC / pargs.period; - if (pwm->period != NSEC_PER_SEC / clk_pwm->fixed_rate && - pwm->period != DIV_ROUND_UP(NSEC_PER_SEC, clk_pwm->fixed_rate)) { + if (pargs.period != NSEC_PER_SEC / clk_pwm->fixed_rate && + pargs.period != DIV_ROUND_UP(NSEC_PER_SEC, clk_pwm->fixed_rate)) { dev_err(&pdev->dev, "clock-frequency does not match PWM period\n"); return -EINVAL; } - ret = pwm_config(pwm, (pwm->period + 1) >> 1, pwm->period); + /* + * FIXME: pwm_apply_args() should be removed when switching to the + * atomic PWM API. + */ + pwm_apply_args(pwm); + ret = pwm_config(pwm, (pargs.period + 1) >> 1, pargs.period); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a0788763757b..8357d571553a 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1638,6 +1638,12 @@ static int pwm_setup_backlight(struct intel_connector *connector, return -ENODEV; } + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(panel->backlight.pwm); + retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS, CRC_PMIC_PWM_PERIOD_NS); if (retval < 0) { diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 3e23003f78b0..f9af3935b427 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -40,15 +40,18 @@ struct pwm_fan_ctx { static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { + struct pwm_args pargs; unsigned long duty; int ret = 0; + pwm_get_args(ctx->pwm, &pargs); + mutex_lock(&ctx->lock); if (ctx->pwm_value == pwm) goto exit_set_pwm_err; - duty = DIV_ROUND_UP(pwm * (ctx->pwm->period - 1), MAX_PWM); - ret = pwm_config(ctx->pwm, duty, ctx->pwm->period); + duty = DIV_ROUND_UP(pwm * (pargs.period - 1), MAX_PWM); + ret = pwm_config(ctx->pwm, duty, pargs.period); if (ret) goto exit_set_pwm_err; @@ -215,6 +218,7 @@ static int pwm_fan_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; struct pwm_fan_ctx *ctx; + struct pwm_args pargs; struct device *hwmon; int duty_cycle; int ret; @@ -233,11 +237,19 @@ static int pwm_fan_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); + /* + * FIXME: pwm_apply_args() should be removed when switching to the + * atomic PWM API. + */ + pwm_apply_args(ctx->pwm); + /* Set duty cycle to maximum allowed */ - duty_cycle = ctx->pwm->period - 1; + pwm_get_args(ctx->pwm, &pargs); + + duty_cycle = pargs.period - 1; ctx->pwm_value = MAX_PWM; - ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->period); + ret = pwm_config(ctx->pwm, duty_cycle, pargs.period); if (ret) { dev_err(&pdev->dev, "Failed to configure PWM\n"); return ret; @@ -303,14 +315,16 @@ static int pwm_fan_suspend(struct device *dev) static int pwm_fan_resume(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + struct pwm_args pargs; unsigned long duty; int ret; if (ctx->pwm_value == 0) return 0; - duty = DIV_ROUND_UP(ctx->pwm_value * (ctx->pwm->period - 1), MAX_PWM); - ret = pwm_config(ctx->pwm, duty, ctx->pwm->period); + pwm_get_args(ctx->pwm, &pargs); + duty = DIV_ROUND_UP(ctx->pwm_value * (pargs.period - 1), MAX_PWM); + ret = pwm_config(ctx->pwm, duty, pargs.period); if (ret) return ret; return pwm_enable(ctx->pwm); diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 6d96bff32a0e..29ddeb7be84b 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -70,10 +70,13 @@ struct max77693_haptic { static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) { - int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2; + struct pwm_args pargs; + int delta; int error; - error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period); + pwm_get_args(haptic->pwm_dev, &pargs); + delta = (pargs.period + haptic->pwm_duty) / 2; + error = pwm_config(haptic->pwm_dev, delta, pargs.period); if (error) { dev_err(haptic->dev, "failed to configure pwm: %d\n", error); return error; @@ -234,6 +237,7 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { struct max77693_haptic *haptic = input_get_drvdata(dev); + struct pwm_args pargs; u64 period_mag_multi; haptic->magnitude = effect->u.rumble.strong_magnitude; @@ -245,7 +249,8 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data, * The formula to convert magnitude to pwm_duty as follows: * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF) */ - period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude; + pwm_get_args(haptic->pwm_dev, &pargs); + period_mag_multi = (u64)pargs.period * haptic->magnitude; haptic->pwm_duty = (unsigned int)(period_mag_multi >> MAX_MAGNITUDE_SHIFT); @@ -329,6 +334,12 @@ static int max77693_haptic_probe(struct platform_device *pdev) return PTR_ERR(haptic->pwm_dev); } + /* + * FIXME: pwm_apply_args() should be removed when switching to the + * atomic PWM API. + */ + pwm_apply_args(haptic->pwm_dev); + haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic"); if (IS_ERR(haptic->motor_reg)) { dev_err(&pdev->dev, "failed to get regulator\n"); diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 8d6326d7e7be..99bc762881d5 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -306,6 +306,12 @@ static int max8997_haptic_probe(struct platform_device *pdev) error); goto err_free_mem; } + + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(chip->pwm); break; default: diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index f2261ab54701..8d7133268745 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -87,6 +87,12 @@ static int pwm_beeper_probe(struct platform_device *pdev) goto err_free; } + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(beeper->pwm); + beeper->input = input_allocate_device(); if (!beeper->input) { dev_err(&pdev->dev, "Failed to allocate input device\n"); diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 4783bacb2e9d..a9145aa7f36a 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -91,6 +91,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, struct led_pwm *led, struct device_node *child) { struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; + struct pwm_args pargs; int ret; led_data->active_low = led->active_low; @@ -117,7 +118,15 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, else led_data->cdev.brightness_set_blocking = led_pwm_set_blocking; - led_data->period = pwm_get_period(led_data->pwm); + /* + * FIXME: pwm_apply_args() should be removed when switching to the + * atomic PWM API. + */ + pwm_apply_args(led_data->pwm); + + pwm_get_args(led_data->pwm, &pargs); + + led_data->period = pargs.period; if (!led_data->period && (led->pwm_period_ns > 0)) led_data->period = led->pwm_period_ns; diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 680fbc795a0a..dba3843c53b8 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -75,6 +75,7 @@ static void free_pwms(struct pwm_chip *chip) for (i = 0; i < chip->npwm; i++) { struct pwm_device *pwm = &chip->pwms[i]; + radix_tree_delete(&pwm_tree, pwm->pwm); } @@ -128,13 +129,6 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) set_bit(PWMF_REQUESTED, &pwm->flags); pwm->label = label; - /* - * FIXME: This should be removed once all PWM users properly make use - * of struct pwm_args to initialize the PWM device. As long as this is - * here, the PWM state and hardware state can get out of sync. - */ - pwm_apply_args(pwm); - return 0; } @@ -233,6 +227,19 @@ void *pwm_get_chip_data(struct pwm_device *pwm) } EXPORT_SYMBOL_GPL(pwm_get_chip_data); +static bool pwm_ops_check(const struct pwm_ops *ops) +{ + /* driver supports legacy, non-atomic operation */ + if (ops->config && ops->enable && ops->disable) + return true; + + /* driver supports atomic operation */ + if (ops->apply) + return true; + + return false; +} + /** * pwmchip_add_with_polarity() - register a new PWM chip * @chip: the PWM chip to add @@ -251,8 +258,10 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, unsigned int i; int ret; - if (!chip || !chip->dev || !chip->ops || !chip->ops->config || - !chip->ops->enable || !chip->ops->disable || !chip->npwm) + if (!chip || !chip->dev || !chip->ops || !chip->npwm) + return -EINVAL; + + if (!pwm_ops_check(chip->ops)) return -EINVAL; mutex_lock(&pwm_lock); @@ -261,7 +270,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, if (ret < 0) goto out; - chip->pwms = kzalloc(chip->npwm * sizeof(*pwm), GFP_KERNEL); + chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); if (!chip->pwms) { ret = -ENOMEM; goto out; @@ -275,8 +284,10 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, pwm->chip = chip; pwm->pwm = chip->base + i; pwm->hwpwm = i; - pwm->polarity = polarity; - mutex_init(&pwm->lock); + pwm->state.polarity = polarity; + + if (chip->ops->get_state) + chip->ops->get_state(chip, pwm, &pwm->state); radix_tree_insert(&pwm_tree, pwm->pwm, pwm); } @@ -436,107 +447,138 @@ void pwm_free(struct pwm_device *pwm) EXPORT_SYMBOL_GPL(pwm_free); /** - * pwm_config() - change a PWM device configuration + * pwm_apply_state() - atomically apply a new state to a PWM device * @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. + * @state: new state to apply. This can be adjusted by the PWM driver + * if the requested config is not achievable, for example, + * ->duty_cycle and ->period might be approximated. */ -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) { int err; - if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns) + if (!pwm) return -EINVAL; - 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; + if (!memcmp(state, &pwm->state, sizeof(*state))) + return 0; - return 0; -} -EXPORT_SYMBOL_GPL(pwm_config); + if (pwm->chip->ops->apply) { + err = pwm->chip->ops->apply(pwm->chip, pwm, state); + if (err) + return err; -/** - * pwm_set_polarity() - configure the polarity of a PWM signal - * @pwm: PWM device - * @polarity: new polarity of the PWM signal - * - * 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; + pwm->state = *state; + } else { + /* + * FIXME: restore the initial state in case of error. + */ + if (state->polarity != pwm->state.polarity) { + if (!pwm->chip->ops->set_polarity) + return -ENOTSUPP; + + /* + * Changing the polarity of a running PWM is + * only allowed when the PWM driver implements + * ->apply(). + */ + if (pwm->state.enabled) { + pwm->chip->ops->disable(pwm->chip, pwm); + pwm->state.enabled = false; + } + + err = pwm->chip->ops->set_polarity(pwm->chip, pwm, + state->polarity); + if (err) + return err; + + pwm->state.polarity = state->polarity; + } - if (!pwm || !pwm->chip->ops) - return -EINVAL; + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) { + err = pwm->chip->ops->config(pwm->chip, pwm, + state->duty_cycle, + state->period); + if (err) + return err; - if (!pwm->chip->ops->set_polarity) - return -ENOSYS; + pwm->state.duty_cycle = state->duty_cycle; + pwm->state.period = state->period; + } - mutex_lock(&pwm->lock); + if (state->enabled != pwm->state.enabled) { + if (state->enabled) { + err = pwm->chip->ops->enable(pwm->chip, pwm); + if (err) + return err; + } else { + pwm->chip->ops->disable(pwm->chip, pwm); + } - if (pwm_is_enabled(pwm)) { - err = -EBUSY; - goto unlock; + pwm->state.enabled = state->enabled; + } } - err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); - if (err) - goto unlock; - - pwm->polarity = polarity; - -unlock: - mutex_unlock(&pwm->lock); - return err; + return 0; } -EXPORT_SYMBOL_GPL(pwm_set_polarity); +EXPORT_SYMBOL_GPL(pwm_apply_state); /** - * pwm_enable() - start a PWM output toggling + * pwm_adjust_config() - adjust the current PWM config to the PWM arguments * @pwm: PWM device * - * Returns: 0 on success or a negative error code on failure. + * 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_enable(struct pwm_device *pwm) +int pwm_adjust_config(struct pwm_device *pwm) { - int err = 0; + struct pwm_state state; + struct pwm_args pargs; - if (!pwm) - return -EINVAL; + pwm_get_args(pwm, &pargs); + pwm_get_state(pwm, &state); - mutex_lock(&pwm->lock); + /* + * 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; - 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); + return pwm_apply_state(pwm, &state); } - mutex_unlock(&pwm->lock); + /* + * 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; - return err; -} -EXPORT_SYMBOL_GPL(pwm_enable); + do_div(dutycycle, state.period); + state.duty_cycle = dutycycle; + state.period = pargs.period; + } -/** - * pwm_disable() - stop a PWM output toggling - * @pwm: PWM device - */ -void pwm_disable(struct pwm_device *pwm) -{ - if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags)) - pwm->chip->ops->disable(pwm->chip, pwm); + /* + * 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_state(pwm, &state); } -EXPORT_SYMBOL_GPL(pwm_disable); +EXPORT_SYMBOL_GPL(pwm_adjust_config); static struct pwm_chip *of_node_to_pwmchip(struct device_node *np) { @@ -754,13 +796,13 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) if (!chip) goto out; - pwm->args.period = chosen->period; - pwm->args.polarity = chosen->polarity; - pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id); if (IS_ERR(pwm)) goto out; + pwm->args.period = chosen->period; + pwm->args.polarity = chosen->polarity; + out: mutex_unlock(&pwm_lookup_lock); return pwm; @@ -907,15 +949,23 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) for (i = 0; i < chip->npwm; i++) { struct pwm_device *pwm = &chip->pwms[i]; + struct pwm_state state; + + pwm_get_state(pwm, &state); seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label); if (test_bit(PWMF_REQUESTED, &pwm->flags)) seq_puts(s, " requested"); - if (pwm_is_enabled(pwm)) + if (state.enabled) seq_puts(s, " enabled"); + seq_printf(s, " period: %u ns", state.period); + seq_printf(s, " duty: %u ns", state.duty_cycle); + seq_printf(s, " polarity: %s", + state.polarity ? "inverse" : "normal"); + seq_puts(s, "\n"); } } diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 7101c7020bf4..bd0ebd04856a 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -75,7 +75,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm, return -EINVAL; } - if (pwm->period != period_ns) { + if (pwm_get_period(pwm) != period_ns) { int clk_div; /* changing the clk divisor, need to disable fisrt */ diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 9861fed4e67d..19dc64cab2f0 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -249,7 +249,7 @@ static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event), LPC18XX_PWM_EVSTATEMSK_ALL); - if (pwm->polarity == PWM_POLARITY_NORMAL) { + if (pwm_get_polarity(pwm) == PWM_POLARITY_NORMAL) { set_event = lpc18xx_pwm->period_event; clear_event = lpc18xx_data->duty_event; res_action = LPC18XX_PWM_RES_SET; diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index b7e6ecba7d5c..3e95090cd7cf 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -192,7 +192,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, load_value, load_value, match_value, match_value); omap->pdata->set_pwm(omap->dm_timer, - pwm->polarity == PWM_POLARITY_INVERSED, + pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED, true, PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 7b8ac0678137..1c85ecc9e7ac 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -157,7 +157,7 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, return div; /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ - if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns) + if (!pwm_is_enabled(pwm) && !duty_ns) return 0; rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 67af9f62361f..03a99a53c39e 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -354,7 +354,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev) val = sun4i_pwm_readl(pwm, PWM_CTRL_REG); for (i = 0; i < pwm->chip.npwm; i++) if (!(val & BIT_CH(PWM_ACT_STATE, i))) - pwm->chip.pwms[i].polarity = PWM_POLARITY_INVERSED; + pwm_set_polarity(&pwm->chip.pwms[i], + PWM_POLARITY_INVERSED); clk_disable_unprepare(pwm->clk); return 0; diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 9c90886f4123..d98599249a05 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -26,6 +26,7 @@ struct pwm_export { struct device child; struct pwm_device *pwm; + struct mutex lock; }; static struct pwm_export *child_to_pwm_export(struct device *child) @@ -45,15 +46,20 @@ static ssize_t period_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_state state; - return sprintf(buf, "%u\n", pwm_get_period(pwm)); + pwm_get_state(pwm, &state); + + return sprintf(buf, "%u\n", state.period); } static ssize_t period_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { - struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + struct pwm_state state; unsigned int val; int ret; @@ -61,7 +67,11 @@ static ssize_t period_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val); + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.period = val; + ret = pwm_apply_state(pwm, &state); + mutex_unlock(&export->lock); return ret ? : size; } @@ -71,15 +81,20 @@ static ssize_t duty_cycle_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_state state; + + pwm_get_state(pwm, &state); - return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); + return sprintf(buf, "%u\n", state.duty_cycle); } static ssize_t duty_cycle_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { - struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + struct pwm_state state; unsigned int val; int ret; @@ -87,7 +102,11 @@ static ssize_t duty_cycle_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, val, pwm_get_period(pwm)); + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.duty_cycle = val; + ret = pwm_apply_state(pwm, &state); + mutex_unlock(&export->lock); return ret ? : size; } @@ -97,33 +116,46 @@ static ssize_t enable_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_state state; + + pwm_get_state(pwm, &state); - return sprintf(buf, "%d\n", pwm_is_enabled(pwm)); + return sprintf(buf, "%d\n", state.enabled); } static ssize_t enable_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { - struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + struct pwm_state state; int val, ret; ret = kstrtoint(buf, 0, &val); if (ret) return ret; + mutex_lock(&export->lock); + + pwm_get_state(pwm, &state); + switch (val) { case 0: - pwm_disable(pwm); + state.enabled = false; break; case 1: - ret = pwm_enable(pwm); + state.enabled = true; break; default: ret = -EINVAL; - break; + goto unlock; } + pwm_apply_state(pwm, &state); + +unlock: + mutex_unlock(&export->lock); return ret ? : size; } @@ -133,8 +165,11 @@ static ssize_t polarity_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); const char *polarity = "unknown"; + struct pwm_state state; + + pwm_get_state(pwm, &state); - switch (pwm_get_polarity(pwm)) { + switch (state.polarity) { case PWM_POLARITY_NORMAL: polarity = "normal"; break; @@ -151,8 +186,10 @@ static ssize_t polarity_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { - struct pwm_device *pwm = child_to_pwm_device(child); + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; enum pwm_polarity polarity; + struct pwm_state state; int ret; if (sysfs_streq(buf, "normal")) @@ -162,7 +199,11 @@ static ssize_t polarity_store(struct device *child, else return -EINVAL; - ret = pwm_set_polarity(pwm, polarity); + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + state.polarity = polarity; + ret = pwm_apply_state(pwm, &state); + mutex_unlock(&export->lock); return ret ? : size; } @@ -203,6 +244,7 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) } export->pwm = pwm; + mutex_init(&export->lock); export->child.release = pwm_export_release; export->child.parent = parent; diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 35fe4825a454..60d6c2ac87aa 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -162,7 +162,7 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip) static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) { - unsigned int period = pwm_get_period(pchip->pwmd); + unsigned int period = pchip->pdata->pwm_period; unsigned int duty = br * period / br_max; pwm_config(pchip->pwmd, duty, period); @@ -424,8 +424,13 @@ static int lm3630a_probe(struct i2c_client *client, dev_err(&client->dev, "fail : get pwm device\n"); return PTR_ERR(pchip->pwmd); } + + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(pchip->pwmd); } - pchip->pwmd->period = pdata->pwm_period; /* interrupt enable : irq 0 is not allowed */ pchip->irq = client->irq; diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index daca9e6a2bb3..e5b14f52628f 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -246,6 +246,12 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) return; lp->pwm = pwm; + + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(pwm); } pwm_config(lp->pwm, duty, period); diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index 5d583d7a517b..cf869ec90cce 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -145,6 +145,12 @@ static void lp8788_pwm_ctrl(struct lp8788_bl *bl, int br, int max_br) } bl->pwm = pwm; + + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(pwm); } pwm_config(bl->pwm, duty, period); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 64f9e1b8655f..b2b366bb0f97 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -201,6 +201,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct pwm_bl_data *pb; int initial_blank = FB_BLANK_UNBLANK; + struct pwm_args pargs; int ret; if (!data) { @@ -307,16 +308,21 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(pb->pwm); + + /* * The DT case will set the pwm_period_ns field to 0 and store the * period, parsed from the DT, in the PWM device. For the non-DT case, * set the period from platform data if it has not already been set * via the PWM lookup table. */ - pb->period = pwm_get_period(pb->pwm); - if (!pb->period && (data->pwm_period_ns > 0)) { + pwm_get_args(pb->pwm, &pargs); + pb->period = pargs.period; + if (!pb->period && (data->pwm_period_ns > 0)) pb->period = data->pwm_period_ns; - pwm_set_period(pb->pwm, data->pwm_period_ns); - } pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale); diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 21dafe53ca49..a9c45c89b15e 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -286,6 +286,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) { int ret; u32 precharge, dclk, com_invdir, compins; + struct pwm_args pargs; if (par->device_info->need_pwm) { par->pwm = pwm_get(&par->client->dev, NULL); @@ -294,7 +295,15 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) return PTR_ERR(par->pwm); } - par->pwm_period = pwm_get_period(par->pwm); + /* + * FIXME: pwm_apply_args() should be removed when switching to + * the atomic PWM API. + */ + pwm_apply_args(par->pwm); + + pwm_get_args(par->pwm, &pargs); + + par->pwm_period = pargs.period; /* Enable the PWM */ pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period); pwm_enable(par->pwm); |