Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6bddec0 authored by Lukasz Majewski's avatar Lukasz Majewski Committed by Guenter Roeck
Browse files

hwmon: (pwm-fan) Add support for using PWM FAN as a cooling device



The PWM FAN device can now be used as a thermal cooling device.

Signed-off-by: default avatarLukasz Majewski <l.majewski@samsung.com>
Acked-by: default avatarEduardo Valentin <edubezval@gmail.com>
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 2e5219c7
Loading
Loading
Loading
Loading
+88 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>

#define MAX_PWM 255

@@ -34,6 +35,7 @@ struct pwm_fan_ctx {
	unsigned int pwm_fan_state;
	unsigned int pwm_fan_max_state;
	unsigned int *pwm_fan_cooling_levels;
	struct thermal_cooling_device *cdev;
};

static int  __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
@@ -68,6 +70,17 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
	return ret;
}

static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm)
{
	int i;

	for (i = 0; i < ctx->pwm_fan_max_state; ++i)
		if (pwm < ctx->pwm_fan_cooling_levels[i + 1])
			break;

	ctx->pwm_fan_state = i;
}

static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
		       const char *buf, size_t count)
{
@@ -82,6 +95,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
	if (ret)
		return ret;

	pwm_fan_update_state(ctx, pwm);
	return count;
}

@@ -103,6 +117,62 @@ static struct attribute *pwm_fan_attrs[] = {

ATTRIBUTE_GROUPS(pwm_fan);

/* thermal cooling device callbacks */
static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
				 unsigned long *state)
{
	struct pwm_fan_ctx *ctx = cdev->devdata;

	if (!ctx)
		return -EINVAL;

	*state = ctx->pwm_fan_max_state;

	return 0;
}

static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev,
				 unsigned long *state)
{
	struct pwm_fan_ctx *ctx = cdev->devdata;

	if (!ctx)
		return -EINVAL;

	*state = ctx->pwm_fan_state;

	return 0;
}

static int
pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
	struct pwm_fan_ctx *ctx = cdev->devdata;
	int ret;

	if (!ctx || (state > ctx->pwm_fan_max_state))
		return -EINVAL;

	if (state == ctx->pwm_fan_state)
		return 0;

	ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
	if (ret) {
		dev_err(&cdev->device, "Cannot set pwm!\n");
		return ret;
	}

	ctx->pwm_fan_state = state;

	return ret;
}

static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {
	.get_max_state = pwm_fan_get_max_state,
	.get_cur_state = pwm_fan_get_cur_state,
	.set_cur_state = pwm_fan_set_cur_state,
};

int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx)
{
	struct device_node *np = dev->of_node;
@@ -145,8 +215,9 @@ int pwm_fan_of_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx)

static int pwm_fan_probe(struct platform_device *pdev)
{
	struct device *hwmon;
	struct thermal_cooling_device *cdev;
	struct pwm_fan_ctx *ctx;
	struct device *hwmon;
	int duty_cycle;
	int ret;

@@ -193,6 +264,21 @@ static int pwm_fan_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	ctx->pwm_fan_state = ctx->pwm_fan_max_state;
	if (IS_ENABLED(CONFIG_THERMAL)) {
		cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
							  "pwm-fan", ctx,
							  &pwm_fan_cooling_ops);
		if (IS_ERR(cdev)) {
			dev_err(&pdev->dev,
				"Failed to register pwm-fan as cooling device");
			pwm_disable(ctx->pwm);
			return PTR_ERR(cdev);
		}
		ctx->cdev = cdev;
		thermal_cdev_update(cdev);
	}

	return 0;
}

@@ -200,6 +286,7 @@ static int pwm_fan_remove(struct platform_device *pdev)
{
	struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);

	thermal_cooling_device_unregister(ctx->cdev);
	if (ctx->pwm_value)
		pwm_disable(ctx->pwm);
	return 0;