From patchwork Wed Sep 14 15:31:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 1677951 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=E04LbOy8; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=e1l8ZBIQ; dkim-atps=neutral Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MSPT45XPrz1ypZ for ; Thu, 15 Sep 2022 01:31:52 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229638AbiINPbt (ORCPT ); Wed, 14 Sep 2022 11:31:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42454 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229690AbiINPbs (ORCPT ); Wed, 14 Sep 2022 11:31:48 -0400 Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D3B9750700; Wed, 14 Sep 2022 08:31:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169507; x=1694705507; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WM+xIdPpk5wsGwY+EBkuixZH3uS2Jyz3uzB0NBE5Q3k=; b=E04LbOy8t4tccSnSG00tuUe7kxj1oMBa1w+Nh+RH8pVEO8T02/Bz6ge4 CErxje0B/G+4VvSSr6/BYPzpFCn1D0w6SY1Ri/2vS4qz212P5DogZonb4 RipUt4UvMeKFP0x5/K8n5YScGSb2wFS8LwwyzesTvcFyr2vsIW1evZNn7 naxzJSJjAMXoAKJCH4/knYLz4b3/vJNagz4iyki1vZMM8YBbnItO3VScn EhCwFzZkzrsY9YXA+vtFmscjvt+cBl/4Aymewevwv/XcHpFhQeuTMM4X8 O7WeaRcs4VsLJAO6u+os2J7IYEGD1MThvClSilNA6081cN9qbA6HXMPRp A==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181299" Received: from unknown (HELO tq-pgp-pr1.tq-net.de) ([192.168.6.15]) by mx1-pgp.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from mx1.tq-group.com ([192.168.6.7]) by tq-pgp-pr1.tq-net.de (PGP Universal service); Wed, 14 Sep 2022 17:31:44 +0200 X-PGP-Universal: processed; by tq-pgp-pr1.tq-net.de on Wed, 14 Sep 2022 17:31:44 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169504; x=1694705504; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WM+xIdPpk5wsGwY+EBkuixZH3uS2Jyz3uzB0NBE5Q3k=; b=e1l8ZBIQ36TVBcdaZU1MXuzLIw3pzc6lrcKToWJDn9jYcHUd7t7S10t5 HpOSnK/9Z4+GTqrmKUzyJ7DGFKJ8fBkFnzQ72pWk7/MXRa4BRaX3PtjZm N6kGGA8Kl97s/q4phzyuu+hYmi/nWOKlA0GczZTnpo7RaMrxNasQ9Sl80 LKznogmhpCBIiRjEzQpakkeASHsuj4SVxOFhG3yNysKtYxFzhCfk1UENX 4pFxQWKdEDPZGAdRahxmDyqmEuDP6JKvrHo76OepNIBioFh+wlk7Dy/NU CdelbAOUTDBxTDkPvRXBXa36YfXT4xNe47ASAtEN6XfQiwEOi2ifJ/BLr g==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181298" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from steina-w.tq-net.de (unknown [10.123.49.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id 0C2D3280072; Wed, 14 Sep 2022 17:31:44 +0200 (CEST) From: Alexander Stein To: Jean Delvare , Guenter Roeck , Jonathan Corbet , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lee Jones Cc: Alexander Stein , linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, Markus Niebel Subject: [PATCH v5 1/5] hwmon: pwm-fan: Refactor fan power on/off Date: Wed, 14 Sep 2022 17:31:33 +0200 Message-Id: <20220914153137.613982-2-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> References: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org 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 --- drivers/hwmon/pwm-fan.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) 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; From patchwork Wed Sep 14 15:31:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 1677952 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=UVf1hz7N; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=oYGfkcbI; dkim-atps=neutral Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MSPT51qHGz1yhR for ; Thu, 15 Sep 2022 01:31:53 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229774AbiINPbu (ORCPT ); Wed, 14 Sep 2022 11:31:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229751AbiINPbs (ORCPT ); Wed, 14 Sep 2022 11:31:48 -0400 Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D3A852E68; Wed, 14 Sep 2022 08:31:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169507; x=1694705507; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=W5vAyTiInp3pwLtLIS4sxMRlr7rQja3WJIBXzAKb0BI=; b=UVf1hz7NUcaQxBtKmain85sdswtK555bgTPAumRRQZ2mdfmqRrPR0Ht3 iyYkYo6mRGLLmeHjO7Q4Y/uaaBtTQOfsjAjWG7NgDE6kFCkRGqa2x1WIC tbNDGJQdvWj1ty4McPhkEh2hnIW0LqXofE+lCdqKxCn5Ie3IkkInnxdEx Y5brWhmtbWClIj7MFc+4EblnUtXkzQ6XaPhpXAAZ8Lybfs9NMo88bmVE9 hZNC+LlsnyZzFIPT8+9FflKGszkxezODopBcPFOvAvV7DUa7VBiGAkPKf SGSUAJ7WxMU5aQM0dwFNSgqiOJa1SKWgKF5LfhSYe2ia5Ct2TLLPCCIfk w==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181301" Received: from unknown (HELO tq-pgp-pr1.tq-net.de) ([192.168.6.15]) by mx1-pgp.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from mx1.tq-group.com ([192.168.6.7]) by tq-pgp-pr1.tq-net.de (PGP Universal service); Wed, 14 Sep 2022 17:31:44 +0200 X-PGP-Universal: processed; by tq-pgp-pr1.tq-net.de on Wed, 14 Sep 2022 17:31:44 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169504; x=1694705504; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=W5vAyTiInp3pwLtLIS4sxMRlr7rQja3WJIBXzAKb0BI=; b=oYGfkcbIe81V3a67qeZfEFbMmxRXugAAdSgfUbhPpmlg8sBYVkkfSdFU Xuk/XEgojOeuPkDwDXVNbpRiE1aOd7aO2CbBlQm5siKIHt9Tf1zYIoq1X yu9fLZ0jMoNVVHuVY+zs/H7s1BC8tUtx+GYuqRd0ktjgaNEtgZrnzySrI P8W2PnoHv09rS/luAmWoIlL4f4CHTxuCZdQ+0gwe7grVYcrwW/sYBpPNw 4KS80IA38xYjKWImDd6FNlNo53EAqLTuvfKtOxvjUD8/HZAs2i7Ktm5Xw AzZdNk8hkH27gyUCHMRKjwfM8rOivJBYGxbVtYmlyBLQSpByXSuhblQHV g==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181300" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from steina-w.tq-net.de (unknown [10.123.49.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id 3ABED280056; Wed, 14 Sep 2022 17:31:44 +0200 (CEST) From: Alexander Stein To: Jean Delvare , Guenter Roeck , Jonathan Corbet , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lee Jones Cc: Alexander Stein , linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, Markus Niebel Subject: [PATCH v5 2/5] hwmon: pwm-fan: Simplify enable/disable check Date: Wed, 14 Sep 2022 17:31:34 +0200 Message-Id: <20220914153137.613982-3-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> References: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org 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 --- drivers/hwmon/pwm-fan.c | 43 ++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) 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"); From patchwork Wed Sep 14 15:31:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 1677953 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=JCopAZ3U; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=TNx2rb7v; dkim-atps=neutral Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MSPT54x2Dz1ypZ for ; Thu, 15 Sep 2022 01:31:53 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229667AbiINPbu (ORCPT ); Wed, 14 Sep 2022 11:31:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42466 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229770AbiINPbt (ORCPT ); Wed, 14 Sep 2022 11:31:49 -0400 Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5540A4455F; Wed, 14 Sep 2022 08:31:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169508; x=1694705508; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=85aJxQmKurDkYSP1FJQw3TqELhxhuad70Kc3ZbTLiDU=; b=JCopAZ3UxZkFbmCtdPYkBFq77fhwhJtRvfwHCSWYBpTGpcVyetXtWY/h PlHH/I5MsqPU3Tu5hBLnCp+8G7KjC6StkOfQ/QdqKfX6XfAaAvI/3wLhT cm90SRv+1YGC6CE/52WFCodc5yC8OIp2PfVOUG1SAO3SJZZeStzofMgLy X5P2v/LAFO+ZpnIciowt3n/41xWUxRWs9S4BzdaRw4f3bgNg4csm9Qn1a BBcfL+Xp6S10k0PAKWhEEcckD4bA1T8qYT1ifz/r3t2xkwFurxiMlGf9N NYKqn3q0jd40u/5qtg9TZnR6cl3ieSgUW0YyaM0ctLKUcAiL5/Tb+6GLD w==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181305" Received: from unknown (HELO tq-pgp-pr1.tq-net.de) ([192.168.6.15]) by mx1-pgp.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from mx1.tq-group.com ([192.168.6.7]) by tq-pgp-pr1.tq-net.de (PGP Universal service); Wed, 14 Sep 2022 17:31:44 +0200 X-PGP-Universal: processed; by tq-pgp-pr1.tq-net.de on Wed, 14 Sep 2022 17:31:44 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169504; x=1694705504; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=85aJxQmKurDkYSP1FJQw3TqELhxhuad70Kc3ZbTLiDU=; b=TNx2rb7vlJsNyykDsNrCbfi9QNtwXpZQnzbXLYUPn8tOni0IXiL98Nez It7mhgv561AVkLJZk2jSIZSUIeW/ZaehH+/xGNWXAU8SYrpQO181+kDfU HSrLCbeHBCymHll4QXIUMFrPjl+A7tJ2G+026WtdpjsHdeZwPChtkYOzV qLczwEHa2FdycrZKUESbXz+tUxauRv3qH0+T4jgYJyfIZ/9qFBW4Re2No Hr6Xzo8H9DwKGi7gUzwiNR0HKSqeLskNmizpRFxhKuQp20+M2e0UlaCku LRiR8Lh2kJKbn8fWu7DNWfozjsGhsTq34GZfAdvTx4AwGBioHAGERjd8f A==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181303" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from steina-w.tq-net.de (unknown [10.123.49.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id 6D3BD280073; Wed, 14 Sep 2022 17:31:44 +0200 (CEST) From: Alexander Stein To: Jean Delvare , Guenter Roeck , Jonathan Corbet , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lee Jones Cc: Alexander Stein , linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, Markus Niebel Subject: [PATCH v5 3/5] hwmon: pwm-fan: Add dedicated power switch function Date: Wed, 14 Sep 2022 17:31:35 +0200 Message-Id: <20220914153137.613982-4-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> References: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org 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 --- drivers/hwmon/pwm-fan.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) 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) From patchwork Wed Sep 14 15:31:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 1677954 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=fgyG472Q; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=ZZgw0xbX; dkim-atps=neutral Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MSPT610Gsz1yhR for ; Thu, 15 Sep 2022 01:31:54 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229770AbiINPbw (ORCPT ); Wed, 14 Sep 2022 11:31:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42472 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229542AbiINPbu (ORCPT ); Wed, 14 Sep 2022 11:31:50 -0400 Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1048048CAB; Wed, 14 Sep 2022 08:31:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169509; x=1694705509; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ILty9AwYF/A0k9EWfznOPHbvgTNH+i70Ca8VVGwNl1M=; b=fgyG472QnAZFpy5OH66FDNrVNRB2CtF9p4qyVh2Aniwa4iDg8I8CJsbH 3UsFz7GoxwigZ2va+3Be2De6jpH0t43ivQ0fFY+5HweEZMMHtdZPtkjKZ odey9N04q4EbtKPNk51A7indCa1avN1HmeyFyrRrbopgUzaUxJsEbKVKu 0JL6Xm7RxY3/cWzVC1lYLQDpfepKxIDavkEtpZwrTQhylch5E4rH4kwM6 o5KnFDTs6Amp+rU9aAWsJ5WtnjS8asGYZC/UmFNSztq79QIXByvTNwJdr gaMkGMgAsWn68wXHErDhUxVrbPjytQhMqeIIpIX1D+m2m7QHCIkO/usV4 w==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181306" Received: from unknown (HELO tq-pgp-pr1.tq-net.de) ([192.168.6.15]) by mx1-pgp.tq-group.com with ESMTP; 14 Sep 2022 17:31:45 +0200 Received: from mx1.tq-group.com ([192.168.6.7]) by tq-pgp-pr1.tq-net.de (PGP Universal service); Wed, 14 Sep 2022 17:31:45 +0200 X-PGP-Universal: processed; by tq-pgp-pr1.tq-net.de on Wed, 14 Sep 2022 17:31:45 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169505; x=1694705505; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ILty9AwYF/A0k9EWfznOPHbvgTNH+i70Ca8VVGwNl1M=; b=ZZgw0xbXl5rKp7mbJgEPlyq2ifvcEsp7o6lL/AtuZtIA8sCRIPoKRA2C obVrEixQ8JydMCdZZ4dlhXNcUDylEfpXf1PqEoMD0+Z38xVHrU4EgEcpv 8mHOBMz2gyNuQ7LqoITLHUvRjvKlm/OTDV8xxaF0C2GH0ZpgkMhd6qwYQ mzLpidypHBPxexP51LvQSNn2GYsIu9Q000x3immeAVVYRbmLLuqjkvkzQ 30zMFmLqWEnKDLTnTJXpCITNa7kTR1yBrRVb1QqnSBjufs/7r7aEsYmYB 45h7rnoIYXQA45thiHurvnqjDbh3UHt5IRPslSaxnWsiUX2nSly7sUhB0 w==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181304" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 14 Sep 2022 17:31:44 +0200 Received: from steina-w.tq-net.de (unknown [10.123.49.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id 9BDF9280074; Wed, 14 Sep 2022 17:31:44 +0200 (CEST) From: Alexander Stein To: Jean Delvare , Guenter Roeck , Jonathan Corbet , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lee Jones Cc: Alexander Stein , linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, Markus Niebel Subject: [PATCH v5 4/5] hwmon: pwm-fan: split __set_pwm into locked/unlocked functions Date: Wed, 14 Sep 2022 17:31:36 +0200 Message-Id: <20220914153137.613982-5-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> References: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org 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 --- drivers/hwmon/pwm-fan.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) 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; From patchwork Wed Sep 14 15:31:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Stein X-Patchwork-Id: 1677955 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=YGlwdDzv; dkim=pass (2048-bit key) header.d=tq-group.com header.i=@tq-group.com header.a=rsa-sha256 header.s=key1 header.b=oJ1HeBbU; dkim-atps=neutral Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MSPT64kjZz1yhR for ; Thu, 15 Sep 2022 01:31:54 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229781AbiINPbx (ORCPT ); Wed, 14 Sep 2022 11:31:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229729AbiINPbv (ORCPT ); Wed, 14 Sep 2022 11:31:51 -0400 Received: from mx1.tq-group.com (mx1.tq-group.com [93.104.207.81]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B8F3650700; Wed, 14 Sep 2022 08:31:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169510; x=1694705510; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9MSgq+uShDD573tVQef0Y4B8C8bcCZMWoHJFCeG7/t8=; b=YGlwdDzv+8/PLx9Ax3N0Ho1vxKKYeK0Ugq7sX6ZrzzWR0eoiRmDe+zOi duWDSgoXwx/zb05SKHVaIuD3BbwupJXnsi8LxCvON7NKDUaU/+f6mSYYi Ex2KNwD6mUYvnKrt+wBqsNthO4QXUPzpaHt6wwBa9JmW00Hrst8DVWLzd t5v+5aIslqW4B7+eIvq91AAAc127i0cn4n8e0PSTfYSufaBoh7MjWV0bI vpMpDaDvq6T1D9ZVxPvPVJNJzEa7dPcnZ5tNWHeikSCn6ymQR//QL63oU fs+LIDPr1a98RlKLWQfSLiQrDKcu75qVVZpKwkJhnL6Vbs5fwbnh0AKD3 w==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181308" Received: from unknown (HELO tq-pgp-pr1.tq-net.de) ([192.168.6.15]) by mx1-pgp.tq-group.com with ESMTP; 14 Sep 2022 17:31:45 +0200 Received: from mx1.tq-group.com ([192.168.6.7]) by tq-pgp-pr1.tq-net.de (PGP Universal service); Wed, 14 Sep 2022 17:31:45 +0200 X-PGP-Universal: processed; by tq-pgp-pr1.tq-net.de on Wed, 14 Sep 2022 17:31:45 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tq-group.com; i=@tq-group.com; q=dns/txt; s=key1; t=1663169505; x=1694705505; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9MSgq+uShDD573tVQef0Y4B8C8bcCZMWoHJFCeG7/t8=; b=oJ1HeBbUQQ/ZlJLdHgQg//KR1JuDI8Jh3O5jy+ECCbwqfy9YHOfmDZeD rxuVvO3BJkBIIposAnpAEK5W3mYBXrwgxn4hXKPzjMkQeW7pYTLyhYlwd n9j/6c9XCQCy6tcc7HPPmgq+fvnTXJoymxTT3/fko1TapqKmX4iXz3ZOY GzyGz/+eSlpmui7dxMS9IgBF1J3GybzJHBDaWtQVm+ZMfaA95iPVpjCxW tmYBLBK/8ymAJtlFrgrSB0R4fgoFWW526M/aUeYXzAQMlqowbgHH4v+Yl yLAzu7tZiAfPTk2g1fujuuv7xa3dr0pmG8kauYTsRVKPtmnRZHjHMYiKK g==; X-IronPort-AV: E=Sophos;i="5.93,315,1654552800"; d="scan'208";a="26181307" Received: from vtuxmail01.tq-net.de ([10.115.0.20]) by mx1.tq-group.com with ESMTP; 14 Sep 2022 17:31:45 +0200 Received: from steina-w.tq-net.de (unknown [10.123.49.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by vtuxmail01.tq-net.de (Postfix) with ESMTPSA id CF7BA280056; Wed, 14 Sep 2022 17:31:44 +0200 (CEST) From: Alexander Stein To: Jean Delvare , Guenter Roeck , Jonathan Corbet , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Lee Jones Cc: Alexander Stein , linux-hwmon@vger.kernel.org, linux-pwm@vger.kernel.org, Markus Niebel Subject: [PATCH v5 5/5] hwmon: pwm-fan: Switch regulator dynamically Date: Wed, 14 Sep 2022 17:31:37 +0200 Message-Id: <20220914153137.613982-6-alexander.stein@ew.tq-group.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> References: <20220914153137.613982-1-alexander.stein@ew.tq-group.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org 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 --- Documentation/hwmon/pwm-fan.rst | 12 ++ drivers/hwmon/pwm-fan.c | 210 +++++++++++++++++++++----------- 2 files changed, 154 insertions(+), 68 deletions(-) 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