Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp6002538imu; Wed, 30 Jan 2019 07:12:17 -0800 (PST) X-Google-Smtp-Source: ALg8bN45ctWdMF8EmXZD+7ZH1cBnAwuiaSbr+WMwkzSkZN6yAjD5hKLPwkQ/EmsubwZMA3iFSyK8 X-Received: by 2002:a63:6346:: with SMTP id x67mr27799110pgb.183.1548861137473; Wed, 30 Jan 2019 07:12:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548861137; cv=none; d=google.com; s=arc-20160816; b=A18r48Z2rkTHMvjN4VsaWKie/jmdqU7JQdsNK/O4YpRsSEeZEtGNPzCQfoMuQZ2NJb iiwRTypT4a6BtC+qBurxxZz4nQyaskSCDjM+zIf4q+b9fJ5MCd/XC3kH89n2VkHBFPIv 0ToHHACzX0Y6VqIXSwtgPvOMMNL8+bl4VAsklqabGE7oKNKqwAnPkBITeJrOLdc+WgGh YcO0FXu3jfZubDb/IruI98ApwXjDGPK/+IYE2wNJNs1NcR08/D5RnZ9bnXnDtej1pF/h GLbwUXGNo5vYPbJCM9OPJ8EbOlJLlUu2nKRD25UnnHKAg7HGjkJ+7RwCuR/a/dFilTrf iAgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=vnnBsdqGeRAFFFEyQYeW//CzP/iYquLDuqfX9wXqe6U=; b=t7W/l1veqCn7ZXyFpCJbnUzDdV+/hnIt5CiuCKKcULxaPmoc2BVH4FA+YE+6XU9D8Y tTKfx2Kt7lI5Pcn7EdmUJMjuzkHgr/AYvQgD1Jjode+k5E67n3UpY5HrDIRfH+rtvvdQ EeJ0s+WSOh4TVvNDIKHYfvdluaHUe04PBBTlT/2yKvv3nlx4d8DoqRHdsOdWK0nG1Kxl r6ex8fm+3FkSgJzEolFUl0LorqziroQ21HKWBiQQbr7VSecjMH2h6ZniXVnN88er6KZf xXlpriDVx+pMG1tSevlKf/VnRc71XAcvMCe7RyP4nv67k27SzRoDZSKo6+uq2j961mVo lYXA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x9si1604373pgh.12.2019.01.30.07.11.58; Wed, 30 Jan 2019 07:12:17 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731475AbfA3PJ0 (ORCPT + 99 others); Wed, 30 Jan 2019 10:09:26 -0500 Received: from mout.kundenserver.de ([217.72.192.74]:41587 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728704AbfA3PIe (ORCPT ); Wed, 30 Jan 2019 10:08:34 -0500 Received: from stefan-Vostro-260.fritz.box ([109.104.32.180]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1Mt6x5-1h8J3Q2ZQ1-00tSws; Wed, 30 Jan 2019 16:07:37 +0100 From: Stefan Wahren To: Kamil Debski , Bartlomiej Zolnierkiewicz , Jean Delvare , Guenter Roeck , Rob Herring , Mark Rutland Cc: linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Stefan Wahren Subject: [PATCH RFC 3/3] hwmon: pwm-fan: Add RPM support via external interrupt Date: Wed, 30 Jan 2019 16:07:07 +0100 Message-Id: <1548860827-29796-4-git-send-email-stefan.wahren@i2se.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1548860827-29796-1-git-send-email-stefan.wahren@i2se.com> References: <1548860827-29796-1-git-send-email-stefan.wahren@i2se.com> X-Provags-ID: V03:K1:6PYVM5mOr+jBDqoqPfyVkKi+e0aGZeVm24bfzZGyzxFAih7gpae raII4Co9rIKaOdehU6cr+sKJGKFDK0+LdZ7ext2u1mV+deLQkPbemEULY/35iHFGKT+1YD9 94aJjLzqIID3Ss1/9a8YszSUHfuK8FZR0xqIo5CGkojiQrs/fwK3YOi7frm3nYgYHGW3SDC 15TQNyOBM5d8qcXUoXAKA== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:ix9sLYOMfN0=:37umqU0jLHN7b4sJINs0Ud DSyUoEmuFZ1bxKaWUjHbstLKfIvQQ4scDwG/KrX1XRZ7SCCUQKeB3ugQzFhq994piG3qg0PEK cadW2OWd0jF9XTLPkCiWUUbBEY4T7Z+unaaaaiXFhCxgnFoLr/lQVl4GkLEO3/GfhVpNYFtcN 0Xn/ETEq1FH2sNb1+ITxgWNBZek2S+FtI7se5K95bmQ0CfDx15p1s+mdJkvjasChZUtuKzz0o ecrxEFCShzw0erB1Yzio1RSeiQamgPb6rpR9J4kuJG/TCWFCPapj2fMvTDJNxai5LXa+gAhDt xm4KNrvsek0tySzrHxPrh70P20DO/HL7U6oPX8ZLIakosi6ujZry1Ikii4B9eQnrjfWCf3AtC p4yAjdLk9mN4Utdxw1rMYB9DEmGW3Lds1dOhofcheJm2/m1wc9Ck00xvUvnp8c1y7bWndiJ5k waKevZR32KS1SBo9ZhbWczEULfespHMPhWYtWPwV0pQvZxJav8hnmnjaIOPhXG2UIxD7byMbO 8Y935Ps5SDEK+wTEhg+n9+MP5A4RPB3bizp19To5boVFReOz0xufsOn0Ejro9kS0dZ0yVA9TU k/RtcNHswm6MdtsRHYILdMa2XY7pe614U3FzJ1tipi1a3fLWz8KeoVyZS8eanLIXgfgdu0/cN PGZxXhzgtPSxh4oC6HedzyQ4Iyvv16jzTewOFJQkVlAX6GpbvyjDQvh8u1g1nKqI3fDEhP3ze 4A9i+Kc63MTey8UVxPOiyxWCYVHF+GhIYcpDgytNKjldZ8E+xkRYKmh7814= Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds RPM support to the pwm-fan driver in order to use with fancontrol/pwmconfig. This feature is intended for 2 pulse-per-revolution fans which provides a tachometer output signal. Signed-off-by: Stefan Wahren --- drivers/hwmon/pwm-fan.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 9e0591e..731fdc6 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,13 +27,22 @@ #include #include #include +#include #define MAX_PWM 255 +#define SAMPLE_TIME 1 /* seconds */ +#define PULSE_PER_REVOLUTION 2 struct pwm_fan_ctx { struct mutex lock; struct pwm_device *pwm; struct regulator *reg_en; + + int irq; + unsigned int pulses; + unsigned int rpm; + struct timer_list sample_timer; + unsigned int pwm_value; unsigned int pwm_fan_state; unsigned int pwm_fan_max_state; @@ -40,6 +50,27 @@ struct pwm_fan_ctx { struct thermal_cooling_device *cdev; }; +static irqreturn_t pulse_handler(int irq, void *dev_id) +{ + struct pwm_fan_ctx *ctx = dev_id; + + if (ctx->pulses < INT_MAX / 2) + ctx->pulses++; + + return IRQ_HANDLED; +} + +static void sample_timer(struct timer_list *t) +{ + struct pwm_fan_ctx *ctx = from_timer(ctx, t, sample_timer); + unsigned int pulses; + + pulses = ctx->pulses; + ctx->pulses -= pulses; + ctx->rpm = pulses * 60 / SAMPLE_TIME / PULSE_PER_REVOLUTION; + mod_timer(&ctx->sample_timer, jiffies + (HZ * SAMPLE_TIME)); +} + static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { unsigned long period; @@ -100,11 +131,20 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", ctx->pwm_value); } +static ssize_t rpm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pwm_fan_ctx *ctx = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ctx->rpm); +} static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); +static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0); static struct attribute *pwm_fan_attrs[] = { &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, NULL, }; @@ -263,6 +303,19 @@ static int pwm_fan_probe(struct platform_device *pdev) } } + timer_setup(&ctx->sample_timer, sample_timer, 0); + + ctx->irq = platform_get_irq(pdev, 0); + if (ctx->irq >= 0) { + ret = devm_request_irq(&pdev->dev, ctx->irq, pulse_handler, 0, + pdev->name, ctx); + if (ret) { + dev_err(&pdev->dev, "Can't get interrupt working.\n"); + return ret; + } + mod_timer(&ctx->sample_timer, jiffies + (HZ * SAMPLE_TIME)); + } + hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan", ctx, pwm_fan_groups); if (IS_ERR(hwmon)) { @@ -304,6 +357,8 @@ static int pwm_fan_remove(struct platform_device *pdev) struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); thermal_cooling_device_unregister(ctx->cdev); + del_timer_sync(&ctx->sample_timer); + if (ctx->pwm_value) pwm_disable(ctx->pwm); -- 2.7.4