Loading Documentation/pwm.txt +28 −2 Original line number Diff line number Diff line Loading @@ -42,9 +42,26 @@ variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist. After being requested, a PWM has to be configured using: 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); To start/stop toggling the PWM output use pwm_enable()/pwm_disable(). This API controls both the PWM period/duty_cycle config and the enable/disable state. The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers around pwm_apply_state() and should not be used if the user wants to change several parameter at once. For example, if you see pwm_config() and pwm_{enable,disable}() calls in the same function, this probably means you should switch to pwm_apply_state(). The PWM user API also allows one to query the PWM state with pwm_get_state(). In addition to the PWM state, the PWM API also exposes PWM arguments, which are the reference PWM config one should use on this PWM. PWM arguments are usually platform-specific and allows the PWM user to only care about dutycycle relatively to the full period (like, duty = 50% of the period). struct pwm_args contains 2 fields (period and polarity) and should be used to set the initial PWM config (usually done in the probe function of the PWM user). PWM arguments are retrieved with pwm_get_args(). Using PWMs with the sysfs interface ----------------------------------- Loading Loading @@ -105,6 +122,15 @@ goes low for the remainder of the period. Conversely, a signal with inversed polarity starts low for the duration of the duty cycle and goes high for the remainder of the period. Drivers are encouraged to implement ->apply() instead of the legacy ->enable(), ->disable() and ->config() methods. Doing that should provide atomicity in the PWM config workflow, which is required when the PWM controls a critical device (like a regulator). The implementation of ->get_state() (a method used to retrieve initial PWM state) is also encouraged for the same reason: letting the PWM user know about the current PWM state would allow him to avoid glitches. Locking ------- Loading arch/arm/mach-s3c24xx/mach-rx1950.c +6 −0 Original line number Diff line number Diff line Loading @@ -496,6 +496,12 @@ static int rx1950_backlight_init(struct device *dev) return PTR_ERR(lcd_pwm); } /* * FIXME: pwm_apply_args() should be removed when switching to * the atomic PWM API. */ pwm_apply_args(lcd_pwm); rx1950_lcd_power(1); rx1950_bl_power(1); Loading drivers/clk/clk-pwm.c +12 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading drivers/gpu/drm/i915/intel_panel.c +6 −0 Original line number Diff line number Diff line Loading @@ -1640,6 +1640,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) { Loading drivers/hwmon/pwm-fan.c +20 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading Loading
Documentation/pwm.txt +28 −2 Original line number Diff line number Diff line Loading @@ -42,9 +42,26 @@ variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist. After being requested, a PWM has to be configured using: 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); To start/stop toggling the PWM output use pwm_enable()/pwm_disable(). This API controls both the PWM period/duty_cycle config and the enable/disable state. The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers around pwm_apply_state() and should not be used if the user wants to change several parameter at once. For example, if you see pwm_config() and pwm_{enable,disable}() calls in the same function, this probably means you should switch to pwm_apply_state(). The PWM user API also allows one to query the PWM state with pwm_get_state(). In addition to the PWM state, the PWM API also exposes PWM arguments, which are the reference PWM config one should use on this PWM. PWM arguments are usually platform-specific and allows the PWM user to only care about dutycycle relatively to the full period (like, duty = 50% of the period). struct pwm_args contains 2 fields (period and polarity) and should be used to set the initial PWM config (usually done in the probe function of the PWM user). PWM arguments are retrieved with pwm_get_args(). Using PWMs with the sysfs interface ----------------------------------- Loading Loading @@ -105,6 +122,15 @@ goes low for the remainder of the period. Conversely, a signal with inversed polarity starts low for the duration of the duty cycle and goes high for the remainder of the period. Drivers are encouraged to implement ->apply() instead of the legacy ->enable(), ->disable() and ->config() methods. Doing that should provide atomicity in the PWM config workflow, which is required when the PWM controls a critical device (like a regulator). The implementation of ->get_state() (a method used to retrieve initial PWM state) is also encouraged for the same reason: letting the PWM user know about the current PWM state would allow him to avoid glitches. Locking ------- Loading
arch/arm/mach-s3c24xx/mach-rx1950.c +6 −0 Original line number Diff line number Diff line Loading @@ -496,6 +496,12 @@ static int rx1950_backlight_init(struct device *dev) return PTR_ERR(lcd_pwm); } /* * FIXME: pwm_apply_args() should be removed when switching to * the atomic PWM API. */ pwm_apply_args(lcd_pwm); rx1950_lcd_power(1); rx1950_bl_power(1); Loading
drivers/clk/clk-pwm.c +12 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading
drivers/gpu/drm/i915/intel_panel.c +6 −0 Original line number Diff line number Diff line Loading @@ -1640,6 +1640,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) { Loading
drivers/hwmon/pwm-fan.c +20 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading