Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nzxt-kraken3: PWM setting fixes; status reporting optimization #34

Merged
merged 5 commits into from
Jan 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 39 additions & 28 deletions nzxt-kraken3.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <asm/unaligned.h>

#define USB_VENDOR_ID_NZXT 0x1e71
Expand All @@ -37,7 +38,6 @@ static const char *const kraken3_device_names[] = {
#define STATUS_VALIDITY (4 * STATUS_INTERVAL) /* seconds */
#define CUSTOM_CURVE_POINTS 40 /* For temps from 20C to 59C (critical temp) */
#define PUMP_DUTY_MIN 20 /* In percent */
#define CURVE_DUTY_MAX 100 /* In percent */

/* Sensor report offsets for Kraken X53 and Z53 */
#define TEMP_SENSOR_START_OFFSET 15
Expand Down Expand Up @@ -83,7 +83,11 @@ static const char *const kraken3_fan_label[] = {

struct kraken3_channel_info {
enum pwm_enable mode;
u16 fixed_duty;

/* Both values are PWM */
u16 reported_duty;
u16 fixed_duty; /* Manually set fixed duty */

u8 pwm_points[CUSTOM_CURVE_POINTS];
};

Expand All @@ -101,7 +105,6 @@ struct kraken3_data {
/* Sensor values */
s32 temp_input[1];
u16 fan_input[2];
u8 duty_input[2];

enum kinds kind;
u8 firmware_version[3];
Expand Down Expand Up @@ -197,9 +200,9 @@ static int kraken3_pwm_to_percent(long val, int channel)

percent_value = DIV_ROUND_CLOSEST(val * 100, 255);

/* Pump has a minimum duty value in addition to the max */
if ((channel == 0 && percent_value < PUMP_DUTY_MIN) || percent_value > CURVE_DUTY_MAX)
return -EINVAL;
/* Bring up pump duty to min value if needed */
if (channel == 0 && percent_value < PUMP_DUTY_MIN)
percent_value = PUMP_DUTY_MIN;

return percent_value;
}
Expand All @@ -210,21 +213,23 @@ static int kraken3_read(struct device *dev, enum hwmon_sensor_types type, u32 at
int ret;
struct kraken3_data *priv = dev_get_drvdata(dev);

if (priv->kind == Z53) {
/* Request status on demand */
reinit_completion(&priv->z53_status_processed);
if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ)) {
if (priv->kind == Z53) {
/* Request status on demand */
reinit_completion(&priv->z53_status_processed);

/* Send command for getting status */
ret = kraken3_write_expanded(priv, z53_get_status_cmd, Z53_GET_STATUS_CMD_LENGTH);
if (ret < 0)
return ret;
/* Send command for getting status */
ret = kraken3_write_expanded(priv, z53_get_status_cmd,
Z53_GET_STATUS_CMD_LENGTH);
if (ret < 0)
return ret;

wait_for_completion(&priv->z53_status_processed);
wait_for_completion(&priv->z53_status_processed);
} else {
return -ENODATA;
}
}

if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ))
return -ENODATA;

switch (type) {
case hwmon_temp:
*val = priv->temp_input[channel];
Expand All @@ -238,7 +243,7 @@ static int kraken3_read(struct device *dev, enum hwmon_sensor_types type, u32 at
*val = priv->channel_info[channel].mode;
break;
case hwmon_pwm_input:
*val = kraken3_percent_to_pwm(priv->duty_input[channel]);
*val = priv->channel_info[channel].reported_duty;
break;
default:
break;
Expand Down Expand Up @@ -289,12 +294,12 @@ static int kraken3_write_curve(struct kraken3_data *priv, u8 *curve_array, int c

static int kraken3_write_fixed_duty(struct kraken3_data *priv, long val, int channel)
{
int ret, percent_value, i;
int ret, percent_val, i;
u8 fixed_curve_points[CUSTOM_CURVE_POINTS];

percent_value = kraken3_pwm_to_percent(val, channel);
if (percent_value < 0)
return percent_value;
percent_val = kraken3_pwm_to_percent(val, channel);
if (percent_val < 0)
return percent_val;

/*
* The devices can only control the duty through a curve.
Expand All @@ -306,7 +311,7 @@ static int kraken3_write_fixed_duty(struct kraken3_data *priv, long val, int cha

/* Fill the custom curve with the fixed value we're setting */
for (i = 0; i < CUSTOM_CURVE_POINTS - 1; i++)
fixed_curve_points[i] = percent_value;
fixed_curve_points[i] = percent_val;

/* Force duty to 100% at critical temp */
fixed_curve_points[CUSTOM_CURVE_POINTS - 1] = 100;
Expand All @@ -333,6 +338,12 @@ static int kraken3_write(struct device *dev, enum hwmon_sensor_types type, u32 a
ret = kraken3_write_fixed_duty(priv, val, channel);
if (ret < 0)
return ret;

/*
* Lock onto this value and report it until next interrupt status
* report is received, so userspace tools can continue to work
*/
priv->channel_info[channel].reported_duty = val;
}
break;
case hwmon_pwm_enable:
Expand Down Expand Up @@ -404,9 +415,8 @@ static ssize_t kraken3_fan_curve_pwm_store(struct device *dev, struct device_att
if (priv->channel_info[dev_attr->nr].mode == curve) {
/* Apply the curve */
ret =
kraken3_write_curve(priv,
priv->channel_info[dev_attr->nr].pwm_points,
dev_attr->nr);
kraken3_write_curve(priv,
priv->channel_info[dev_attr->nr].pwm_points, dev_attr->nr);
if (ret < 0)
return ret;
}
Expand Down Expand Up @@ -666,12 +676,13 @@ static int kraken3_raw_event(struct hid_device *hdev, struct hid_report *report,
data[TEMP_SENSOR_START_OFFSET] * 1000 + data[TEMP_SENSOR_END_OFFSET] * 100;

priv->fan_input[0] = get_unaligned_le16(data + PUMP_SPEED_OFFSET);
priv->duty_input[0] = data[PUMP_DUTY_OFFSET];
priv->channel_info[0].reported_duty = kraken3_percent_to_pwm(data[PUMP_DUTY_OFFSET]);

/* Additional readings for Z53 */
if (priv->kind == Z53) {
priv->fan_input[1] = get_unaligned_le16(data + Z53_FAN_SPEED_OFFSET);
priv->duty_input[1] = data[Z53_FAN_DUTY_OFFSET];
priv->channel_info[1].reported_duty =
kraken3_percent_to_pwm(data[Z53_FAN_DUTY_OFFSET]);

complete(&priv->z53_status_processed);
}
Expand Down