Skip to content

Commit fa4dac3

Browse files
MisterZ42groeck
authored andcommitted
hwmon: (corsair-cpro) add reading pwm values
This adds the possibility for reading pwm values. These can not be read if the device is controlled via fan_target or a fan curve and will return an error in this case. Since an error is expected, this adds some rudimentary error handling. Changes: - add CTL_GET_FAN_PWM and use it via get_data - pwm returns -ENODATA if the device returns error 0x12 - fan_target now returns -ENODATA when the driver is started or a pwm value is set. - add ccp_get_errno to determine errno from device error. - get_data now has a parameter to determine whether to read one or two bytes of data. - update documentation - fix missing surname in MAINTAINERS Signed-off-by: Marius Zachmann <[email protected]> Signed-off-by: Guenter Roeck <[email protected]>
1 parent e492217 commit fa4dac3

File tree

3 files changed

+48
-25
lines changed

3 files changed

+48
-25
lines changed

Documentation/hwmon/corsair-cpro.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ fan[1-6]_input Connected fan rpm.
3535
fan[1-6]_label Shows fan type as detected by the device.
3636
fan[1-6]_target Sets fan speed target rpm.
3737
When reading, it reports the last value if it was set by the driver.
38-
Otherwise returns 0.
39-
pwm[1-6] Sets the fan speed. Values from 0-255.
40-
When reading, it reports the last value if it was set by the driver.
41-
Otherwise returns 0.
38+
Otherwise returns an error.
39+
pwm[1-6] Sets the fan speed. Values from 0-255. Can only be read if pwm
40+
was set directly.
4241
======================= =====================================================================

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4402,7 +4402,7 @@ F: Documentation/hwmon/coretemp.rst
44024402
F: drivers/hwmon/coretemp.c
44034403

44044404
CORSAIR-CPRO HARDWARE MONITOR DRIVER
4405-
M: Marius <[email protected]>
4405+
M: Marius Zachmann <[email protected]>
44064406
44074407
S: Maintained
44084408
F: drivers/hwmon/corsair-cpro.c

drivers/hwmon/corsair-cpro.c

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@
3636
* send: byte 1 is channel, rest zero
3737
* rcv: returns temp for channel in centi-degree celsius
3838
* in bytes 1 and 2
39-
* returns 17 in byte 0 if no sensor is connected
39+
* returns 0x11 in byte 0 if no sensor is connected
4040
*/
4141
#define CTL_GET_VOLT 0x12 /*
4242
* send: byte 1 is rail number: 0 = 12v, 1 = 5v, 2 = 3.3v
4343
* rcv: returns millivolt in bytes 1,2
44+
* returns error 0x10 if request is invalid
4445
*/
4546
#define CTL_GET_FAN_CNCT 0x20 /*
4647
* returns in bytes 1-6 for each fan:
@@ -52,6 +53,12 @@
5253
* send: byte 1 is channel, rest zero
5354
* rcv: returns rpm in bytes 1,2
5455
*/
56+
#define CTL_GET_FAN_PWM 0x22 /*
57+
* send: byte 1 is channel, rest zero
58+
* rcv: returns pwm in byte 1 if it was set
59+
* returns error 0x12 if fan is controlled via
60+
* fan_target or fan curve
61+
*/
5562
#define CTL_SET_FAN_FPWM 0x23 /*
5663
* set fixed pwm
5764
* send: byte 1 is fan number
@@ -73,13 +80,31 @@ struct ccp_device {
7380
struct completion wait_input_report;
7481
struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */
7582
u8 *buffer;
76-
int pwm[6];
7783
int target[6];
7884
DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS);
7985
DECLARE_BITMAP(fan_cnct, NUM_FANS);
8086
char fan_label[6][LABEL_LENGTH];
8187
};
8288

89+
/* converts response error in buffer to errno */
90+
static int ccp_get_errno(struct ccp_device *ccp)
91+
{
92+
switch (ccp->buffer[0]) {
93+
case 0x00: /* success */
94+
return 0;
95+
case 0x01: /* called invalid command */
96+
return -EOPNOTSUPP;
97+
case 0x10: /* called GET_VOLT / GET_TMP with invalid arguments */
98+
return -EINVAL;
99+
case 0x11: /* requested temps of disconnected sensors */
100+
case 0x12: /* requested pwm of not pwm controlled channels */
101+
return -ENODATA;
102+
default:
103+
hid_dbg(ccp->hdev, "unknown device response error: %d", ccp->buffer[0]);
104+
return -EIO;
105+
}
106+
}
107+
83108
/* send command, check for error in response, response in ccp->buffer */
84109
static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, u8 byte3)
85110
{
@@ -102,13 +127,7 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2,
102127
if (!t)
103128
return -ETIMEDOUT;
104129

105-
/* first byte of response is error code */
106-
if (ccp->buffer[0] != 0x00) {
107-
hid_dbg(ccp->hdev, "device response error: %d", ccp->buffer[0]);
108-
return -EIO;
109-
}
110-
111-
return 0;
130+
return ccp_get_errno(ccp);
112131
}
113132

114133
static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)
@@ -126,7 +145,7 @@ static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8
126145
}
127146

128147
/* requests and returns single data values depending on channel */
129-
static int get_data(struct ccp_device *ccp, int command, int channel)
148+
static int get_data(struct ccp_device *ccp, int command, int channel, bool two_byte_data)
130149
{
131150
int ret;
132151

@@ -136,7 +155,9 @@ static int get_data(struct ccp_device *ccp, int command, int channel)
136155
if (ret)
137156
goto out_unlock;
138157

139-
ret = (ccp->buffer[1] << 8) + ccp->buffer[2];
158+
ret = ccp->buffer[1];
159+
if (two_byte_data)
160+
ret = (ret << 8) + ccp->buffer[2];
140161

141162
out_unlock:
142163
mutex_unlock(&ccp->mutex);
@@ -150,14 +171,14 @@ static int set_pwm(struct ccp_device *ccp, int channel, long val)
150171
if (val < 0 || val > 255)
151172
return -EINVAL;
152173

153-
ccp->pwm[channel] = val;
154-
155174
/* The Corsair Commander Pro uses values from 0-100 */
156175
val = DIV_ROUND_CLOSEST(val * 100, 255);
157176

158177
mutex_lock(&ccp->mutex);
159178

160179
ret = send_usb_cmd(ccp, CTL_SET_FAN_FPWM, channel, val, 0);
180+
if (!ret)
181+
ccp->target[channel] = -ENODATA;
161182

162183
mutex_unlock(&ccp->mutex);
163184
return ret;
@@ -171,7 +192,6 @@ static int set_target(struct ccp_device *ccp, int channel, long val)
171192
ccp->target[channel] = val;
172193

173194
mutex_lock(&ccp->mutex);
174-
175195
ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
176196

177197
mutex_unlock(&ccp->mutex);
@@ -210,7 +230,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
210230
case hwmon_temp:
211231
switch (attr) {
212232
case hwmon_temp_input:
213-
ret = get_data(ccp, CTL_GET_TMP, channel);
233+
ret = get_data(ccp, CTL_GET_TMP, channel, true);
214234
if (ret < 0)
215235
return ret;
216236
*val = ret * 10;
@@ -222,14 +242,16 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
222242
case hwmon_fan:
223243
switch (attr) {
224244
case hwmon_fan_input:
225-
ret = get_data(ccp, CTL_GET_FAN_RPM, channel);
245+
ret = get_data(ccp, CTL_GET_FAN_RPM, channel, true);
226246
if (ret < 0)
227247
return ret;
228248
*val = ret;
229249
return 0;
230250
case hwmon_fan_target:
231251
/* how to read target values from the device is unknown */
232252
/* driver returns last set value or 0 */
253+
if (ccp->target[channel] < 0)
254+
return -ENODATA;
233255
*val = ccp->target[channel];
234256
return 0;
235257
default:
@@ -239,9 +261,10 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
239261
case hwmon_pwm:
240262
switch (attr) {
241263
case hwmon_pwm_input:
242-
/* how to read pwm values from the device is currently unknown */
243-
/* driver returns last set value or 0 */
244-
*val = ccp->pwm[channel];
264+
ret = get_data(ccp, CTL_GET_FAN_PWM, channel, false);
265+
if (ret < 0)
266+
return ret;
267+
*val = DIV_ROUND_CLOSEST(ret * 255, 100);
245268
return 0;
246269
default:
247270
break;
@@ -250,7 +273,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
250273
case hwmon_in:
251274
switch (attr) {
252275
case hwmon_in_input:
253-
ret = get_data(ccp, CTL_GET_VOLT, channel);
276+
ret = get_data(ccp, CTL_GET_VOLT, channel, true);
254277
if (ret < 0)
255278
return ret;
256279
*val = ret;
@@ -416,6 +439,7 @@ static int get_fan_cnct(struct ccp_device *ccp)
416439
continue;
417440

418441
set_bit(channel, ccp->fan_cnct);
442+
ccp->target[channel] = -ENODATA;
419443

420444
switch (mode) {
421445
case 1:

0 commit comments

Comments
 (0)