From 2e2aa25cf5b0de2a2eb7da124c42184fc76d7afe Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 26 Aug 2022 20:26:40 +0300 Subject: hwmon: (pwm-fan) Replace OF specific call to PWM by plain one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to call OF specific devm_of_pwm_get() since the device node parameter duplicates in the device parameter. Hence we may safely replace it by plain devm_pwm_get() call. This allows to drop devm_of_pwm_get() as no more users will be. Signed-off-by: Andy Shevchenko Acked-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220826172642.16404-1-andriy.shevchenko@linux.intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 6c08551d8d14..06fd1d75101d 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -302,7 +302,7 @@ static int pwm_fan_probe(struct platform_device *pdev) mutex_init(&ctx->lock); - ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL); + ctx->pwm = devm_pwm_get(dev, NULL); if (IS_ERR(ctx->pwm)) return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); -- cgit v1.2.3 From bf10ccad068088f4e31f4d4266356d1d24cf5734 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Sep 2022 17:31:33 +0200 Subject: hwmon: (pwm-fan) Refactor fan power on/off In preparation for dynamically switching regulator, split the power on and power off sequence into separate functions. Signed-off-by: Alexander Stein Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220914153137.613982-2-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 06fd1d75101d..c8a7926d39e7 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -82,23 +82,47 @@ static void sample_timer(struct timer_list *t) mod_timer(&ctx->rpm_timer, jiffies + HZ); } -static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) { + struct pwm_state *state = &ctx->pwm_state; unsigned long period; - int ret = 0; + int ret; + + period = state->period; + state->duty_cycle = DIV_ROUND_UP(ctx->pwm_value * (period - 1), MAX_PWM); + state->enabled = true; + ret = pwm_apply_state(ctx->pwm, state); + + return ret; +} + +static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) +{ struct pwm_state *state = &ctx->pwm_state; + state->enabled = false; + state->duty_cycle = 0; + pwm_apply_state(ctx->pwm, state); + + return 0; +} + +static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +{ + int ret = 0; + mutex_lock(&ctx->lock); if (ctx->pwm_value == pwm) goto exit_set_pwm_err; - period = state->period; - state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); - state->enabled = pwm ? true : false; + if (pwm > 0) + ret = pwm_fan_power_on(ctx); + else + ret = pwm_fan_power_off(ctx); - ret = pwm_apply_state(ctx->pwm, state); if (!ret) ctx->pwm_value = pwm; + exit_set_pwm_err: mutex_unlock(&ctx->lock); return ret; -- cgit v1.2.3 From b77f0c7680a4df2a550be5e0158204de1aa3a3ce Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Sep 2022 17:31:34 +0200 Subject: hwmon: (pwm-fan) Simplify enable/disable check Instead of comparing the current to the new pwm duty to decide whether to enable the PWM, use a dedicated flag. Also apply the new PWM duty in any case. This is a preparation to enable/disable the regulator dynamically. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220914153137.613982-3-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index c8a7926d39e7..01412c71deb3 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -29,10 +29,13 @@ struct pwm_fan_tach { }; struct pwm_fan_ctx { + struct device *dev; + struct mutex lock; struct pwm_device *pwm; struct pwm_state pwm_state; struct regulator *reg_en; + bool enabled; int tach_count; struct pwm_fan_tach *tachs; @@ -85,13 +88,19 @@ static void sample_timer(struct timer_list *t) static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) { struct pwm_state *state = &ctx->pwm_state; - unsigned long period; int ret; - period = state->period; - state->duty_cycle = DIV_ROUND_UP(ctx->pwm_value * (period - 1), MAX_PWM); + if (ctx->enabled) + return 0; + state->enabled = true; ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to enable PWM\n"); + return ret; + } + + ctx->enabled = true; return ret; } @@ -99,27 +108,42 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) { struct pwm_state *state = &ctx->pwm_state; + int ret; + + if (!ctx->enabled) + return 0; state->enabled = false; state->duty_cycle = 0; - pwm_apply_state(ctx->pwm, state); + ret = pwm_apply_state(ctx->pwm, state); + if (ret) { + dev_err(ctx->dev, "failed to disable PWM\n"); + return ret; + } + + ctx->enabled = false; return 0; } static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { + struct pwm_state *state = &ctx->pwm_state; + unsigned long period; int ret = 0; mutex_lock(&ctx->lock); - if (ctx->pwm_value == pwm) - goto exit_set_pwm_err; - if (pwm > 0) + if (pwm > 0) { + period = state->period; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + ret = pwm_apply_state(ctx->pwm, state); + if (ret) + goto exit_set_pwm_err; ret = pwm_fan_power_on(ctx); - else + } else { ret = pwm_fan_power_off(ctx); - + } if (!ret) ctx->pwm_value = pwm; @@ -326,6 +350,7 @@ static int pwm_fan_probe(struct platform_device *pdev) mutex_init(&ctx->lock); + ctx->dev = &pdev->dev; ctx->pwm = devm_pwm_get(dev, NULL); if (IS_ERR(ctx->pwm)) return dev_err_probe(dev, PTR_ERR(ctx->pwm), "Could not get PWM\n"); -- cgit v1.2.3 From 9bf3aa60808803d56cb34bdff336e85c87c8026d Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Sep 2022 17:31:35 +0200 Subject: hwmon: (pwm-fan) Add dedicated power switch function This handles enabling/disabling the regulator in a single function, while keeping the enables/disabled balanced. This is a preparation when regulator is switched from different code paths. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220914153137.613982-4-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 01412c71deb3..92c5b7f5ddd6 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -35,6 +35,7 @@ struct pwm_fan_ctx { struct pwm_device *pwm; struct pwm_state pwm_state; struct regulator *reg_en; + bool regulator_enabled; bool enabled; int tach_count; @@ -85,6 +86,25 @@ static void sample_timer(struct timer_list *t) mod_timer(&ctx->rpm_timer, jiffies + HZ); } +static int pwm_fan_switch_power(struct pwm_fan_ctx *ctx, bool on) +{ + int ret = 0; + + if (!ctx->reg_en) + return ret; + + if (!ctx->regulator_enabled && on) { + ret = regulator_enable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = true; + } else if (ctx->regulator_enabled && !on) { + ret = regulator_disable(ctx->reg_en); + if (ret == 0) + ctx->regulator_enabled = false; + } + return ret; +} + static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) { struct pwm_state *state = &ctx->pwm_state; @@ -320,7 +340,7 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, static void pwm_fan_regulator_disable(void *data) { - regulator_disable(data); + pwm_fan_switch_power(data, false); } static void pwm_fan_pwm_disable(void *__ctx) @@ -364,13 +384,13 @@ static int pwm_fan_probe(struct platform_device *pdev) ctx->reg_en = NULL; } else { - ret = regulator_enable(ctx->reg_en); + ret = pwm_fan_switch_power(ctx, true); if (ret) { dev_err(dev, "Failed to enable fan supply: %d\n", ret); return ret; } ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable, - ctx->reg_en); + ctx); if (ret) return ret; } @@ -516,12 +536,10 @@ static int pwm_fan_disable(struct device *dev) return ret; } - if (ctx->reg_en) { - ret = regulator_disable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to disable fan supply: %d\n", ret); - return ret; - } + ret = pwm_fan_switch_power(ctx, false); + if (ret) { + dev_err(dev, "Failed to disable fan supply: %d\n", ret); + return ret; } return 0; @@ -543,12 +561,10 @@ static int pwm_fan_resume(struct device *dev) struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); int ret; - if (ctx->reg_en) { - ret = regulator_enable(ctx->reg_en); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } + ret = pwm_fan_switch_power(ctx, true); + if (ret) { + dev_err(dev, "Failed to enable fan supply: %d\n", ret); + return ret; } if (ctx->pwm_value == 0) -- cgit v1.2.3 From 9db6e7f500541b797acc207c790024f6179e2e6c Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Sep 2022 17:31:36 +0200 Subject: hwmon: (pwm-fan) split __set_pwm into locked/unlocked functions Regular calls to set_pwm don't hold the mutex, but the upcoming update_enable support needs to call set_pwm with the mutex being held. So provide the previous behavior in set_pwm (handling the lock), while adding __set_pwm which assumes the lock being held. Signed-off-by: Alexander Stein Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220914153137.613982-5-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 92c5b7f5ddd6..12ef3b3dbe22 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -152,14 +152,12 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) unsigned long period; int ret = 0; - mutex_lock(&ctx->lock); - if (pwm > 0) { period = state->period; state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); ret = pwm_apply_state(ctx->pwm, state); if (ret) - goto exit_set_pwm_err; + return ret; ret = pwm_fan_power_on(ctx); } else { ret = pwm_fan_power_off(ctx); @@ -167,8 +165,17 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) if (!ret) ctx->pwm_value = pwm; -exit_set_pwm_err: + return ret; +} + +static int set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) +{ + int ret; + + mutex_lock(&ctx->lock); + ret = __set_pwm(ctx, pwm); mutex_unlock(&ctx->lock); + return ret; } @@ -192,7 +199,7 @@ static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type, if (val < 0 || val > MAX_PWM) return -EINVAL; - ret = __set_pwm(ctx, val); + ret = set_pwm(ctx, val); if (ret) return ret; @@ -280,7 +287,7 @@ pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) if (state == ctx->pwm_fan_state) return 0; - ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); + ret = set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]); if (ret) { dev_err(&cdev->device, "Cannot set pwm!\n"); return ret; @@ -398,7 +405,7 @@ static int pwm_fan_probe(struct platform_device *pdev) pwm_init_state(ctx->pwm, &ctx->pwm_state); /* - * __set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned + * set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned * long. Check this here to prevent the fan running at a too low * frequency. */ @@ -408,7 +415,7 @@ static int pwm_fan_probe(struct platform_device *pdev) } /* Set duty cycle to maximum allowed and enable PWM output */ - ret = __set_pwm(ctx, MAX_PWM); + ret = set_pwm(ctx, MAX_PWM); if (ret) { dev_err(dev, "Failed to configure PWM: %d\n", ret); return ret; -- cgit v1.2.3 From b99152d4f04b379e31db6c1a2dda6b272c92039b Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 14 Sep 2022 17:31:37 +0200 Subject: hwmon: (pwm-fan) Switch regulator dynamically This adds the enable attribute which is used to select if zero PWM duty means to switch off regulator and PWM or to keep them enabled but at inactive PWM output level. Depending on the select enable mode, turn off the regulator and PWM if the PWM duty is zero, or keep them enabled. This is especially important for fan using inverted PWM signal polarity. Having regulator supplied and PWM disabled, some PWM controllers provide the active, rather than inactive signal. With this change the shutdown as well as suspend/resume paths require modifcations as well. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220914153137.613982-6-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/pwm-fan.rst | 12 +++ drivers/hwmon/pwm-fan.c | 210 +++++++++++++++++++++++++++------------- 2 files changed, 154 insertions(+), 68 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/Documentation/hwmon/pwm-fan.rst b/Documentation/hwmon/pwm-fan.rst index 82fe96742fee..f77998b204ef 100644 --- a/Documentation/hwmon/pwm-fan.rst +++ b/Documentation/hwmon/pwm-fan.rst @@ -18,3 +18,15 @@ the hwmon's sysfs interface. The fan rotation speed returned via the optional 'fan1_input' is extrapolated from the sampled interrupts from the tachometer signal within 1 second. + +The driver provides the following sensor accesses in sysfs: + +=============== ======= ======================================================= +fan1_input ro fan tachometer speed in RPM +pwm1_enable rw keep enable mode, defines behaviour when pwm1=0 + 0 -> disable pwm and regulator + 1 -> enable pwm; if pwm==0, disable pwm, keep regulator enabled + 2 -> enable pwm; if pwm==0, keep pwm and regulator enabled + 3 -> enable pwm; if pwm==0, disable pwm and regulator +pwm1 rw relative speed (0-255), 255=max. speed. +=============== ======= ======================================================= diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 12ef3b3dbe22..498128eb81f1 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -28,6 +28,13 @@ struct pwm_fan_tach { u8 pulses_per_revolution; }; +enum pwm_fan_enable_mode { + pwm_off_reg_off, + pwm_disable_reg_enable, + pwm_enable_reg_enable, + pwm_disable_reg_disable, +}; + struct pwm_fan_ctx { struct device *dev; @@ -35,6 +42,7 @@ struct pwm_fan_ctx { struct pwm_device *pwm; struct pwm_state pwm_state; struct regulator *reg_en; + enum pwm_fan_enable_mode enable_mode; bool regulator_enabled; bool enabled; @@ -86,6 +94,29 @@ static void sample_timer(struct timer_list *t) mod_timer(&ctx->rpm_timer, jiffies + HZ); } +static void pwm_fan_enable_mode_2_state(int enable_mode, + struct pwm_state *state, + bool *enable_regulator) +{ + switch (enable_mode) { + case pwm_disable_reg_enable: + /* disable pwm, keep regulator enabled */ + state->enabled = false; + *enable_regulator = true; + break; + case pwm_enable_reg_enable: + /* keep pwm and regulator enabled */ + state->enabled = true; + *enable_regulator = true; + break; + case pwm_off_reg_off: + case pwm_disable_reg_disable: + /* disable pwm and regulator */ + state->enabled = false; + *enable_regulator = false; + } +} + static int pwm_fan_switch_power(struct pwm_fan_ctx *ctx, bool on) { int ret = 0; @@ -113,26 +144,41 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx) if (ctx->enabled) return 0; + ret = pwm_fan_switch_power(ctx, true); + if (ret < 0) { + dev_err(ctx->dev, "failed to enable power supply\n"); + return ret; + } + state->enabled = true; ret = pwm_apply_state(ctx->pwm, state); if (ret) { dev_err(ctx->dev, "failed to enable PWM\n"); - return ret; + goto disable_regulator; } ctx->enabled = true; + return 0; + +disable_regulator: + pwm_fan_switch_power(ctx, false); return ret; } static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) { struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; int ret; if (!ctx->enabled) return 0; + pwm_fan_enable_mode_2_state(ctx->enable_mode, + state, + &enable_regulator); + state->enabled = false; state->duty_cycle = 0; ret = pwm_apply_state(ctx->pwm, state); @@ -141,6 +187,8 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx) return ret; } + pwm_fan_switch_power(ctx, enable_regulator); + ctx->enabled = false; return 0; @@ -153,6 +201,10 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) int ret = 0; if (pwm > 0) { + if (ctx->enable_mode == pwm_off_reg_off) + /* pwm-fan hard disabled */ + return 0; + period = state->period; state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); ret = pwm_apply_state(ctx->pwm, state); @@ -190,20 +242,76 @@ static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm) ctx->pwm_fan_state = i; } +static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val) +{ + int ret = 0; + int old_val; + + mutex_lock(&ctx->lock); + + if (ctx->enable_mode == val) + goto out; + + old_val = ctx->enable_mode; + ctx->enable_mode = val; + + if (val == 0) { + /* Disable pwm-fan unconditionally */ + ret = __set_pwm(ctx, 0); + if (ret) + ctx->enable_mode = old_val; + pwm_fan_update_state(ctx, 0); + } else { + /* + * Change PWM and/or regulator state if currently disabled + * Nothing to do if currently enabled + */ + if (!ctx->enabled) { + struct pwm_state *state = &ctx->pwm_state; + bool enable_regulator = false; + + state->duty_cycle = 0; + pwm_fan_enable_mode_2_state(val, + state, + &enable_regulator); + + pwm_apply_state(ctx->pwm, state); + pwm_fan_switch_power(ctx, enable_regulator); + pwm_fan_update_state(ctx, 0); + } + } +out: + mutex_unlock(&ctx->lock); + + return ret; +} + static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); int ret; - if (val < 0 || val > MAX_PWM) - return -EINVAL; + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > MAX_PWM) + return -EINVAL; + ret = set_pwm(ctx, val); + if (ret) + return ret; + pwm_fan_update_state(ctx, val); + break; + case hwmon_pwm_enable: + if (val < 0 || val > 3) + ret = -EINVAL; + else + ret = pwm_fan_update_enable(ctx, val); - ret = set_pwm(ctx, val); - if (ret) return ret; + default: + return -EOPNOTSUPP; + } - pwm_fan_update_state(ctx, val); return 0; } @@ -214,9 +322,15 @@ static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type, switch (type) { case hwmon_pwm: - *val = ctx->pwm_value; - return 0; - + switch (attr) { + case hwmon_pwm_input: + *val = ctx->pwm_value; + return 0; + case hwmon_pwm_enable: + *val = ctx->enable_mode; + return 0; + } + return -EOPNOTSUPP; case hwmon_fan: *val = ctx->tachs[channel].rpm; return 0; @@ -345,18 +459,14 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, return 0; } -static void pwm_fan_regulator_disable(void *data) -{ - pwm_fan_switch_power(data, false); -} - -static void pwm_fan_pwm_disable(void *__ctx) +static void pwm_fan_cleanup(void *__ctx) { struct pwm_fan_ctx *ctx = __ctx; - ctx->pwm_state.enabled = false; - pwm_apply_state(ctx->pwm, &ctx->pwm_state); del_timer_sync(&ctx->rpm_timer); + /* Switch off everything */ + ctx->enable_mode = pwm_disable_reg_disable; + pwm_fan_power_off(ctx); } static int pwm_fan_probe(struct platform_device *pdev) @@ -390,16 +500,6 @@ static int pwm_fan_probe(struct platform_device *pdev) return PTR_ERR(ctx->reg_en); ctx->reg_en = NULL; - } else { - ret = pwm_fan_switch_power(ctx, true); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - ret = devm_add_action_or_reset(dev, pwm_fan_regulator_disable, - ctx); - if (ret) - return ret; } pwm_init_state(ctx->pwm, &ctx->pwm_state); @@ -414,14 +514,19 @@ static int pwm_fan_probe(struct platform_device *pdev) return -EINVAL; } - /* Set duty cycle to maximum allowed and enable PWM output */ + ctx->enable_mode = pwm_disable_reg_enable; + + /* + * Set duty cycle to maximum allowed and enable PWM output as well as + * the regulator. In case of error nothing is changed + */ ret = set_pwm(ctx, MAX_PWM); if (ret) { dev_err(dev, "Failed to configure PWM: %d\n", ret); return ret; } timer_setup(&ctx->rpm_timer, sample_timer, 0); - ret = devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx); + ret = devm_add_action_or_reset(dev, pwm_fan_cleanup, ctx); if (ret) return ret; @@ -453,7 +558,7 @@ static int pwm_fan_probe(struct platform_device *pdev) if (!channels) return -ENOMEM; - channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT); + channels[0] = HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE); for (i = 0; i < ctx->tach_count; i++) { struct pwm_fan_tach *tach = &ctx->tachs[i]; @@ -527,57 +632,26 @@ static int pwm_fan_probe(struct platform_device *pdev) return 0; } -static int pwm_fan_disable(struct device *dev) -{ - struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - int ret; - - if (ctx->pwm_value) { - /* keep ctx->pwm_state unmodified for pwm_fan_resume() */ - struct pwm_state state = ctx->pwm_state; - - state.duty_cycle = 0; - state.enabled = false; - ret = pwm_apply_state(ctx->pwm, &state); - if (ret < 0) - return ret; - } - - ret = pwm_fan_switch_power(ctx, false); - if (ret) { - dev_err(dev, "Failed to disable fan supply: %d\n", ret); - return ret; - } - - return 0; -} - static void pwm_fan_shutdown(struct platform_device *pdev) { - pwm_fan_disable(&pdev->dev); + struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); + + pwm_fan_cleanup(ctx); } #ifdef CONFIG_PM_SLEEP static int pwm_fan_suspend(struct device *dev) { - return pwm_fan_disable(dev); + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + return pwm_fan_power_off(ctx); } static int pwm_fan_resume(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); - int ret; - - ret = pwm_fan_switch_power(ctx, true); - if (ret) { - dev_err(dev, "Failed to enable fan supply: %d\n", ret); - return ret; - } - - if (ctx->pwm_value == 0) - return 0; - return pwm_apply_state(ctx->pwm, &ctx->pwm_state); + return set_pwm(ctx, ctx->pwm_value); } #endif -- cgit v1.2.3 From 1839391bdedb23d0e07e9030e18466172818d824 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 25 Sep 2022 18:27:54 +0100 Subject: hwmon: (pwm-fan) Switch to DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr() These newer PM macros allow the compiler to see what code it can remove if !CONFIG_PM_SLEEP. This allows the removal of #ifdef guards whilst achieving the same result. Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220925172759.3573439-14-jic23@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/hwmon/pwm-fan.c') diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 498128eb81f1..dc3d9a22d917 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -639,7 +639,6 @@ static void pwm_fan_shutdown(struct platform_device *pdev) pwm_fan_cleanup(ctx); } -#ifdef CONFIG_PM_SLEEP static int pwm_fan_suspend(struct device *dev) { struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); @@ -653,9 +652,8 @@ static int pwm_fan_resume(struct device *dev) return set_pwm(ctx, ctx->pwm_value); } -#endif -static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume); static const struct of_device_id of_pwm_fan_match[] = { { .compatible = "pwm-fan", }, @@ -668,7 +666,7 @@ static struct platform_driver pwm_fan_driver = { .shutdown = pwm_fan_shutdown, .driver = { .name = "pwm-fan", - .pm = &pwm_fan_pm, + .pm = pm_sleep_ptr(&pwm_fan_pm), .of_match_table = of_pwm_fan_match, }, }; -- cgit v1.2.3