All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC V2 0/3] hwmon: pwm-fan: Add RPM support
@ 2019-02-25 15:59 Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan Stefan Wahren
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Stefan Wahren @ 2019-02-25 15:59 UTC (permalink / raw)
  To: Kamil Debski, Bartlomiej Zolnierkiewicz, Jean Delvare,
	Guenter Roeck, Rob Herring, Mark Rutland
  Cc: linux-hwmon, devicetree, linux-kernel, Stefan Wahren

Contrary to the gpio-fan the pwm-fan driver isn't easy to setup
with pwmconfig/fancontrol because of the missing hwmon sysfs entry
for actual revolutions per minute. This series adds this feature.

Changes in V2:
- address Guenter's comments:
  - improve description of interrupts
  - use atomic_t to avoid races of the pulse counter
  - measure sample time to make rpm more reliable under load
  - make sysfs entry fan1_input conditional
- add dt-property to define interrupts per fan revolution
- example for fan with RPM support

Stefan Wahren (3):
  dt-bindings: hwmon: Add tachometer interrupt to pwm-fan
  Documentation: pwm-fan: Add description for RPM support
  hwmon: pwm-fan: Add RPM support via external interrupt

 .../devicetree/bindings/hwmon/pwm-fan.txt          | 19 +++++
 Documentation/hwmon/pwm-fan                        |  3 +
 drivers/hwmon/pwm-fan.c                            | 94 +++++++++++++++++++++-
 3 files changed, 115 insertions(+), 1 deletion(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan
  2019-02-25 15:59 [PATCH RFC V2 0/3] hwmon: pwm-fan: Add RPM support Stefan Wahren
@ 2019-02-25 15:59 ` Stefan Wahren
  2019-03-12 15:48   ` Rob Herring
  2019-02-25 15:59 ` [PATCH RFC V2 2/3] Documentation: pwm-fan: Add description for RPM support Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 3/3] hwmon: pwm-fan: Add RPM support via external interrupt Stefan Wahren
  2 siblings, 1 reply; 5+ messages in thread
From: Stefan Wahren @ 2019-02-25 15:59 UTC (permalink / raw)
  To: Kamil Debski, Bartlomiej Zolnierkiewicz, Jean Delvare,
	Guenter Roeck, Rob Herring, Mark Rutland
  Cc: linux-hwmon, devicetree, linux-kernel, Stefan Wahren

This adds the tachometer interrupt to the pwm-fan binding, which is
necessary for RPM support.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 Documentation/devicetree/bindings/hwmon/pwm-fan.txt | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
index 49ca5d8..7d09623 100644
--- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
+++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
@@ -8,6 +8,14 @@ Required properties:
 
 Optional properties:
 - fan-supply    : phandle to the regulator that provides power to the fan
+- interrupts      : This contains a single interrupt specifier which
+		    describes the tachometer output of the fan as an
+		    interrupt source. The output signal must generate a
+		    defined number of interrupts per fan revolution, which
+		    require that it must be self resetting edge interrupts.
+		    See interrupt-controller/interrupts.txt for the format.
+- interrupt-ratio : defines the ratio interrupts per fan revolution as an
+		    integer (default is 2 interrupts per revolution)
 
 Example:
 	fan0: pwm-fan {
@@ -38,3 +46,14 @@ Example:
 					};
 			     };
 		};
+
+Example 2:
+	fan0: pwm-fan {
+		fan0: pwm-fan {
+		compatible = "pwm-fan";
+		pwms = <&pwm 0 40000 0>;
+		fan-supply = <&reg_fan>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-ratio = <2>;
+	};
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH RFC V2 2/3] Documentation: pwm-fan: Add description for RPM support
  2019-02-25 15:59 [PATCH RFC V2 0/3] hwmon: pwm-fan: Add RPM support Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan Stefan Wahren
@ 2019-02-25 15:59 ` Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 3/3] hwmon: pwm-fan: Add RPM support via external interrupt Stefan Wahren
  2 siblings, 0 replies; 5+ messages in thread
From: Stefan Wahren @ 2019-02-25 15:59 UTC (permalink / raw)
  To: Kamil Debski, Bartlomiej Zolnierkiewicz, Jean Delvare,
	Guenter Roeck, Rob Herring, Mark Rutland
  Cc: linux-hwmon, devicetree, linux-kernel, Stefan Wahren

This adds a short description for the new RPM support of the pwm-fan
driver.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 Documentation/hwmon/pwm-fan | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/hwmon/pwm-fan b/Documentation/hwmon/pwm-fan
index 18529d2..82fe967 100644
--- a/Documentation/hwmon/pwm-fan
+++ b/Documentation/hwmon/pwm-fan
@@ -15,3 +15,6 @@ The driver implements a simple interface for driving a fan connected to
 a PWM output. It uses the generic PWM interface, thus it can be used with
 a range of SoCs. The driver exposes the fan to the user space through
 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.
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH RFC V2 3/3] hwmon: pwm-fan: Add RPM support via external interrupt
  2019-02-25 15:59 [PATCH RFC V2 0/3] hwmon: pwm-fan: Add RPM support Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan Stefan Wahren
  2019-02-25 15:59 ` [PATCH RFC V2 2/3] Documentation: pwm-fan: Add description for RPM support Stefan Wahren
@ 2019-02-25 15:59 ` Stefan Wahren
  2 siblings, 0 replies; 5+ messages in thread
From: Stefan Wahren @ 2019-02-25 15:59 UTC (permalink / raw)
  To: Kamil Debski, Bartlomiej Zolnierkiewicz, Jean Delvare,
	Guenter Roeck, Rob Herring, Mark Rutland
  Cc: linux-hwmon, devicetree, linux-kernel, Stefan Wahren

This adds RPM support to the pwm-fan driver in order to use with
fancontrol/pwmconfig. This feature is intended for fans with a tachometer
output signal, which generate a defined number of pulses per revolution.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/hwmon/pwm-fan.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 167221c..0bacaba 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -18,6 +18,7 @@
 
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
@@ -26,6 +27,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/sysfs.h>
 #include <linux/thermal.h>
+#include <linux/timer.h>
 
 #define MAX_PWM 255
 
@@ -33,6 +35,14 @@ struct pwm_fan_ctx {
 	struct mutex lock;
 	struct pwm_device *pwm;
 	struct regulator *reg_en;
+
+	int irq;
+	atomic_t pulses;
+	unsigned int rpm;
+	u32 pulse_per_revolution;
+	ktime_t sample_start;
+	struct timer_list rpm_timer;
+
 	unsigned int pwm_value;
 	unsigned int pwm_fan_state;
 	unsigned int pwm_fan_max_state;
@@ -40,6 +50,32 @@ struct pwm_fan_ctx {
 	struct thermal_cooling_device *cdev;
 };
 
+/* This handler assumes self resetting edge triggered interrupt. */
+static irqreturn_t pulse_handler(int irq, void *dev_id)
+{
+	struct pwm_fan_ctx *ctx = dev_id;
+
+	/* Avoid possible overflow */
+	if (atomic_read(&ctx->pulses) < 100000)
+		atomic_inc(&ctx->pulses);
+
+	return IRQ_HANDLED;
+}
+
+static void sample_timer(struct timer_list *t)
+{
+	struct pwm_fan_ctx *ctx = from_timer(ctx, t, rpm_timer);
+	int pulses, sample_ms;
+
+	pulses = atomic_read(&ctx->pulses);
+	atomic_sub(pulses, &ctx->pulses);
+	sample_ms = ktime_ms_delta(ktime_get(), ctx->sample_start);
+	ctx->rpm = pulses * 60 * sample_ms / 1000 / ctx->pulse_per_revolution;
+
+	ctx->sample_start = ktime_get();
+	mod_timer(&ctx->rpm_timer, jiffies + HZ);
+}
+
 static int  __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
 {
 	unsigned long period;
@@ -100,15 +136,49 @@ 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,
 };
 
-ATTRIBUTE_GROUPS(pwm_fan);
+static umode_t pwm_fan_attrs_visible(struct kobject *kobj, struct attribute *a,
+				     int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	struct device_attribute *devattr;
+
+	/* Hide fan_input in case no interrupt is available  */
+	devattr = container_of(a, struct device_attribute, attr);
+	if (devattr == &sensor_dev_attr_fan1_input.dev_attr) {
+		if (ctx->irq < 0)
+			return 0;
+	}
+
+	return a->mode;
+}
+
+static const struct attribute_group pwm_fan_group = {
+	.attrs = pwm_fan_attrs,
+	.is_visible = pwm_fan_attrs_visible,
+};
+
+static const struct attribute_group *pwm_fan_groups[] = {
+	&pwm_fan_group,
+	NULL,
+};
 
 /* thermal cooling device callbacks */
 static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
@@ -261,6 +331,26 @@ static int pwm_fan_probe(struct platform_device *pdev)
 		goto err_reg_disable;
 	}
 
+	timer_setup(&ctx->rpm_timer, sample_timer, 0);
+
+	if (of_property_read_u32(pdev->dev.of_node, "interrupt-ratio",
+				 &ctx->pulse_per_revolution)) {
+		ctx->pulse_per_revolution = 2;
+	}
+
+	atomic_set(&ctx->pulses, 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;
+		}
+		ctx->sample_start = ktime_get();
+		mod_timer(&ctx->rpm_timer, jiffies + HZ);
+	}
+
 	hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan",
 						       ctx, pwm_fan_groups);
 	if (IS_ERR(hwmon)) {
@@ -306,6 +396,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->rpm_timer);
+
 	if (ctx->pwm_value)
 		pwm_disable(ctx->pwm);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan
  2019-02-25 15:59 ` [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan Stefan Wahren
@ 2019-03-12 15:48   ` Rob Herring
  0 siblings, 0 replies; 5+ messages in thread
From: Rob Herring @ 2019-03-12 15:48 UTC (permalink / raw)
  To: Stefan Wahren
  Cc: Kamil Debski, Bartlomiej Zolnierkiewicz, Jean Delvare,
	Guenter Roeck, Mark Rutland, linux-hwmon, devicetree,
	linux-kernel

On Mon, Feb 25, 2019 at 04:59:17PM +0100, Stefan Wahren wrote:
> This adds the tachometer interrupt to the pwm-fan binding, which is
> necessary for RPM support.
> 
> Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
> ---
>  Documentation/devicetree/bindings/hwmon/pwm-fan.txt | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
> index 49ca5d8..7d09623 100644
> --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
> +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
> @@ -8,6 +8,14 @@ Required properties:
>  
>  Optional properties:
>  - fan-supply    : phandle to the regulator that provides power to the fan
> +- interrupts      : This contains a single interrupt specifier which
> +		    describes the tachometer output of the fan as an
> +		    interrupt source. The output signal must generate a
> +		    defined number of interrupts per fan revolution, which
> +		    require that it must be self resetting edge interrupts.
> +		    See interrupt-controller/interrupts.txt for the format.
> +- interrupt-ratio : defines the ratio interrupts per fan revolution as an
> +		    integer (default is 2 interrupts per revolution)

Name this for what it is, not how it is used. Using 'interrupt' is 
misleading that it is related to the interrupt binding.
'tach-pulse-per-rev' or something similar.

>  
>  Example:
>  	fan0: pwm-fan {
> @@ -38,3 +46,14 @@ Example:
>  					};
>  			     };
>  		};
> +
> +Example 2:
> +	fan0: pwm-fan {
> +		fan0: pwm-fan {
> +		compatible = "pwm-fan";
> +		pwms = <&pwm 0 40000 0>;
> +		fan-supply = <&reg_fan>;
> +		interrupt-parent = <&gpio5>;
> +		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
> +		interrupt-ratio = <2>;
> +	};
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-03-12 15:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-25 15:59 [PATCH RFC V2 0/3] hwmon: pwm-fan: Add RPM support Stefan Wahren
2019-02-25 15:59 ` [PATCH RFC V2 1/3] dt-bindings: hwmon: Add tachometer interrupt to pwm-fan Stefan Wahren
2019-03-12 15:48   ` Rob Herring
2019-02-25 15:59 ` [PATCH RFC V2 2/3] Documentation: pwm-fan: Add description for RPM support Stefan Wahren
2019-02-25 15:59 ` [PATCH RFC V2 3/3] hwmon: pwm-fan: Add RPM support via external interrupt Stefan Wahren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.