|
58 | 58 | #define OCP_MULTI_RAIL 0x02
|
59 | 59 |
|
60 | 60 | #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */
|
61 |
| -#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */ |
| 61 | +#define PSU_CMD_FAN_PWM 0x3B /* the rest of the commands expect length 3 */ |
| 62 | +#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 |
62 | 63 | #define PSU_CMD_RAIL_VOLTS_LCRIT 0x44
|
63 | 64 | #define PSU_CMD_RAIL_AMPS_HCRIT 0x46
|
64 | 65 | #define PSU_CMD_TEMP_HCRIT 0x4F
|
|
76 | 77 | #define PSU_CMD_UPTIME 0xD2
|
77 | 78 | #define PSU_CMD_OCPMODE 0xD8
|
78 | 79 | #define PSU_CMD_TOTAL_WATTS 0xEE
|
| 80 | +#define PSU_CMD_FAN_PWM_ENABLE 0xF0 |
79 | 81 | #define PSU_CMD_INIT 0xFE
|
80 | 82 |
|
81 | 83 | #define L_IN_VOLTS "v_in"
|
@@ -145,6 +147,14 @@ static int corsairpsu_linear11_to_int(const u16 val, const int scale)
|
145 | 147 | return (exp >= 0) ? (result << exp) : (result >> -exp);
|
146 | 148 | }
|
147 | 149 |
|
| 150 | +/* the micro-controller uses percentage values to control pwm */ |
| 151 | +static int corsairpsu_dutycycle_to_pwm(const long dutycycle) |
| 152 | +{ |
| 153 | + const int result = (256 << 16) / 100; |
| 154 | + |
| 155 | + return (result * dutycycle) >> 16; |
| 156 | +} |
| 157 | + |
148 | 158 | static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
|
149 | 159 | {
|
150 | 160 | unsigned long time;
|
@@ -264,6 +274,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
|
264 | 274 | case PSU_CMD_FAN:
|
265 | 275 | *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
|
266 | 276 | break;
|
| 277 | + case PSU_CMD_FAN_PWM_ENABLE: |
| 278 | + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); |
| 279 | + /* |
| 280 | + * 0 = automatic mode, means the micro-controller controls the fan using a plan |
| 281 | + * which can be modified, but changing this plan is not supported by this |
| 282 | + * driver, the matching PWM mode is automatic fan speed control = PWM 2 |
| 283 | + * 1 = fixed mode, fan runs at a fixed speed represented by a percentage |
| 284 | + * value 0-100, this matches the PWM manual fan speed control = PWM 1 |
| 285 | + * technically there is no PWM no fan speed control mode, it would be a combination |
| 286 | + * of 1 at 100% |
| 287 | + */ |
| 288 | + if (*val == 0) |
| 289 | + *val = 2; |
| 290 | + break; |
| 291 | + case PSU_CMD_FAN_PWM: |
| 292 | + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); |
| 293 | + *val = corsairpsu_dutycycle_to_pwm(*val); |
| 294 | + break; |
267 | 295 | case PSU_CMD_RAIL_WATTS:
|
268 | 296 | case PSU_CMD_TOTAL_WATTS:
|
269 | 297 | *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000);
|
@@ -349,6 +377,18 @@ static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *pri
|
349 | 377 | }
|
350 | 378 | }
|
351 | 379 |
|
| 380 | +static umode_t corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data *priv, u32 attr, |
| 381 | + int channel) |
| 382 | +{ |
| 383 | + switch (attr) { |
| 384 | + case hwmon_pwm_input: |
| 385 | + case hwmon_pwm_enable: |
| 386 | + return 0444; |
| 387 | + default: |
| 388 | + return 0; |
| 389 | + } |
| 390 | +} |
| 391 | + |
352 | 392 | static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr,
|
353 | 393 | int channel)
|
354 | 394 | {
|
@@ -416,6 +456,8 @@ static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sens
|
416 | 456 | return corsairpsu_hwmon_temp_is_visible(priv, attr, channel);
|
417 | 457 | case hwmon_fan:
|
418 | 458 | return corsairpsu_hwmon_fan_is_visible(priv, attr, channel);
|
| 459 | + case hwmon_pwm: |
| 460 | + return corsairpsu_hwmon_pwm_is_visible(priv, attr, channel); |
419 | 461 | case hwmon_power:
|
420 | 462 | return corsairpsu_hwmon_power_is_visible(priv, attr, channel);
|
421 | 463 | case hwmon_in:
|
@@ -447,6 +489,20 @@ static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, in
|
447 | 489 | return err;
|
448 | 490 | }
|
449 | 491 |
|
| 492 | +static int corsairpsu_hwmon_pwm_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) |
| 493 | +{ |
| 494 | + switch (attr) { |
| 495 | + case hwmon_pwm_input: |
| 496 | + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM, 0, val); |
| 497 | + case hwmon_pwm_enable: |
| 498 | + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM_ENABLE, 0, val); |
| 499 | + default: |
| 500 | + break; |
| 501 | + } |
| 502 | + |
| 503 | + return -EOPNOTSUPP; |
| 504 | +} |
| 505 | + |
450 | 506 | static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel,
|
451 | 507 | long *val)
|
452 | 508 | {
|
@@ -531,6 +587,8 @@ static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types
|
531 | 587 | if (attr == hwmon_fan_input)
|
532 | 588 | return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
|
533 | 589 | return -EOPNOTSUPP;
|
| 590 | + case hwmon_pwm: |
| 591 | + return corsairpsu_hwmon_pwm_read(priv, attr, channel, val); |
534 | 592 | case hwmon_power:
|
535 | 593 | return corsairpsu_hwmon_power_read(priv, attr, channel, val);
|
536 | 594 | case hwmon_in:
|
@@ -579,6 +637,8 @@ static const struct hwmon_channel_info * const corsairpsu_info[] = {
|
579 | 637 | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT),
|
580 | 638 | HWMON_CHANNEL_INFO(fan,
|
581 | 639 | HWMON_F_INPUT | HWMON_F_LABEL),
|
| 640 | + HWMON_CHANNEL_INFO(pwm, |
| 641 | + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), |
582 | 642 | HWMON_CHANNEL_INFO(power,
|
583 | 643 | HWMON_P_INPUT | HWMON_P_LABEL,
|
584 | 644 | HWMON_P_INPUT | HWMON_P_LABEL,
|
|
0 commit comments