xref: /openbmc/linux/drivers/hwmon/aquacomputer_d5next.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
10e35f63fSAleksa Savic // SPDX-License-Identifier: GPL-2.0+
20e35f63fSAleksa Savic /*
3cdbe34daSAleksa Savic  * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
4b3d3be6cSAleksa Savic  * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield)
50e35f63fSAleksa Savic  *
62fd3eec1SAleksa Savic  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
7e0f6c370SAleksa Savic  * sensor values, except for devices that communicate through the
8e0f6c370SAleksa Savic  * legacy way (currently, Poweradjust 3).
90e35f63fSAleksa Savic  *
100e35f63fSAleksa Savic  * Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
11229b159cSJack Doan  * Copyright 2022 Jack Doan <me@jackdoan.com>
120e35f63fSAleksa Savic  */
130e35f63fSAleksa Savic 
14752b9279SAleksa Savic #include <linux/crc16.h>
150e35f63fSAleksa Savic #include <linux/debugfs.h>
16*56b930dcSAleksa Savic #include <linux/delay.h>
170e35f63fSAleksa Savic #include <linux/hid.h>
180e35f63fSAleksa Savic #include <linux/hwmon.h>
190e35f63fSAleksa Savic #include <linux/jiffies.h>
20*56b930dcSAleksa Savic #include <linux/ktime.h>
210e35f63fSAleksa Savic #include <linux/module.h>
22752b9279SAleksa Savic #include <linux/mutex.h>
230e35f63fSAleksa Savic #include <linux/seq_file.h>
242fd3eec1SAleksa Savic #include <asm/unaligned.h>
250e35f63fSAleksa Savic 
262fd3eec1SAleksa Savic #define USB_VENDOR_ID_AQUACOMPUTER	0x0c70
272c552111SLeonard Anderweit #define USB_PRODUCT_ID_AQUAERO		0xf001
28229b159cSJack Doan #define USB_PRODUCT_ID_FARBWERK		0xf00a
29cdbe34daSAleksa Savic #define USB_PRODUCT_ID_QUADRO		0xf00d
302fd3eec1SAleksa Savic #define USB_PRODUCT_ID_D5NEXT		0xf00e
312fd3eec1SAleksa Savic #define USB_PRODUCT_ID_FARBWERK360	0xf010
32752b9279SAleksa Savic #define USB_PRODUCT_ID_OCTO		0xf011
33aed80bb9SAleksa Savic #define USB_PRODUCT_ID_HIGHFLOWNEXT	0xf012
34b3d3be6cSAleksa Savic #define USB_PRODUCT_ID_LEAKSHIELD	0xf014
3519692f17SAleksa Savic #define USB_PRODUCT_ID_AQUASTREAMXT	0xf0b6
367505dab7SAleksa Savic #define USB_PRODUCT_ID_AQUASTREAMULT	0xf00b
37e0f6c370SAleksa Savic #define USB_PRODUCT_ID_POWERADJUST3	0xf0bd
380e35f63fSAleksa Savic 
397505dab7SAleksa Savic enum kinds {
407505dab7SAleksa Savic 	d5next, farbwerk, farbwerk360, octo, quadro,
4119692f17SAleksa Savic 	highflownext, aquaero, poweradjust3, aquastreamult,
42b3d3be6cSAleksa Savic 	aquastreamxt, leakshield
437505dab7SAleksa Savic };
442fd3eec1SAleksa Savic 
452fd3eec1SAleksa Savic static const char *const aqc_device_names[] = {
462fd3eec1SAleksa Savic 	[d5next] = "d5next",
47229b159cSJack Doan 	[farbwerk] = "farbwerk",
48752b9279SAleksa Savic 	[farbwerk360] = "farbwerk360",
49cdbe34daSAleksa Savic 	[octo] = "octo",
50aed80bb9SAleksa Savic 	[quadro] = "quadro",
512c552111SLeonard Anderweit 	[highflownext] = "highflownext",
52b3d3be6cSAleksa Savic 	[leakshield] = "leakshield",
5319692f17SAleksa Savic 	[aquastreamxt] = "aquastreamxt",
54e0f6c370SAleksa Savic 	[aquaero] = "aquaero",
557505dab7SAleksa Savic 	[aquastreamult] = "aquastreamultimate",
56e0f6c370SAleksa Savic 	[poweradjust3] = "poweradjust3"
572fd3eec1SAleksa Savic };
582fd3eec1SAleksa Savic 
592fd3eec1SAleksa Savic #define DRIVER_NAME			"aquacomputer_d5next"
602fd3eec1SAleksa Savic 
612fd3eec1SAleksa Savic #define STATUS_REPORT_ID		0x01
622fd3eec1SAleksa Savic #define STATUS_UPDATE_INTERVAL		(2 * HZ)	/* In seconds */
63ad2f0811SLeonard Anderweit #define SERIAL_PART_OFFSET		2
640e35f63fSAleksa Savic 
65752b9279SAleksa Savic #define CTRL_REPORT_ID			0x03
666c83ccb1SLeonard Anderweit #define AQUAERO_CTRL_REPORT_ID		0x0b
67752b9279SAleksa Savic 
68*56b930dcSAleksa Savic #define CTRL_REPORT_DELAY		200	/* ms */
69*56b930dcSAleksa Savic 
70752b9279SAleksa Savic /* The HID report that the official software always sends
71752b9279SAleksa Savic  * after writing values, currently same for all devices
72752b9279SAleksa Savic  */
73752b9279SAleksa Savic #define SECONDARY_CTRL_REPORT_ID	0x02
74752b9279SAleksa Savic #define SECONDARY_CTRL_REPORT_SIZE	0x0B
75752b9279SAleksa Savic 
76752b9279SAleksa Savic static u8 secondary_ctrl_report[] = {
77752b9279SAleksa Savic 	0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
78752b9279SAleksa Savic };
79752b9279SAleksa Savic 
806c83ccb1SLeonard Anderweit /* Secondary HID report values for Aquaero */
816c83ccb1SLeonard Anderweit #define AQUAERO_SECONDARY_CTRL_REPORT_ID	0x06
826c83ccb1SLeonard Anderweit #define AQUAERO_SECONDARY_CTRL_REPORT_SIZE	0x07
836c83ccb1SLeonard Anderweit 
846c83ccb1SLeonard Anderweit static u8 aquaero_secondary_ctrl_report[] = {
856c83ccb1SLeonard Anderweit 	0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00
866c83ccb1SLeonard Anderweit };
876c83ccb1SLeonard Anderweit 
88e0f6c370SAleksa Savic /* Report IDs for legacy devices */
8919692f17SAleksa Savic #define AQUASTREAMXT_STATUS_REPORT_ID	0x04
9019692f17SAleksa Savic 
91e0f6c370SAleksa Savic #define POWERADJUST3_STATUS_REPORT_ID	0x03
92e0f6c370SAleksa Savic 
93d0450fc1SLeonard Anderweit /* Data types for reading and writing control reports */
94d0450fc1SLeonard Anderweit #define AQC_8		0
95d0450fc1SLeonard Anderweit #define AQC_BE16	1
96d0450fc1SLeonard Anderweit 
972c552111SLeonard Anderweit /* Info, sensor sizes and offsets for most Aquacomputer devices */
98ad2f0811SLeonard Anderweit #define AQC_SERIAL_START		0x3
99ad2f0811SLeonard Anderweit #define AQC_FIRMWARE_VERSION		0xD
100ad2f0811SLeonard Anderweit 
1018bcb02bdSLeonard Anderweit #define AQC_SENSOR_SIZE			0x02
102fdbfd330SAleksa Savic #define AQC_SENSOR_NA			0x7FFF
103654c9735SAleksa Savic #define AQC_FAN_PERCENT_OFFSET		0x00
104654c9735SAleksa Savic #define AQC_FAN_VOLTAGE_OFFSET		0x02
105654c9735SAleksa Savic #define AQC_FAN_CURRENT_OFFSET		0x04
106654c9735SAleksa Savic #define AQC_FAN_POWER_OFFSET		0x06
107654c9735SAleksa Savic #define AQC_FAN_SPEED_OFFSET		0x08
108654c9735SAleksa Savic 
1092c552111SLeonard Anderweit /* Specs of the Aquaero fan controllers */
1102c552111SLeonard Anderweit #define AQUAERO_SERIAL_START			0x07
1112c552111SLeonard Anderweit #define AQUAERO_FIRMWARE_VERSION		0x0B
1122c552111SLeonard Anderweit #define AQUAERO_NUM_FANS			4
1132c552111SLeonard Anderweit #define AQUAERO_NUM_SENSORS			8
1142c552111SLeonard Anderweit #define AQUAERO_NUM_VIRTUAL_SENSORS		8
1153d2e9f58SAleksa Savic #define AQUAERO_NUM_CALC_VIRTUAL_SENSORS	4
1162c552111SLeonard Anderweit #define AQUAERO_NUM_FLOW_SENSORS		2
1176c83ccb1SLeonard Anderweit #define AQUAERO_CTRL_REPORT_SIZE		0xa93
118bd1e92f9SLeonard Anderweit #define AQUAERO_CTRL_PRESET_ID			0x5c
119bd1e92f9SLeonard Anderweit #define AQUAERO_CTRL_PRESET_SIZE		0x02
120bd1e92f9SLeonard Anderweit #define AQUAERO_CTRL_PRESET_START		0x55c
1212c552111SLeonard Anderweit 
1222c552111SLeonard Anderweit /* Sensor report offsets for Aquaero fan controllers */
1232c552111SLeonard Anderweit #define AQUAERO_SENSOR_START			0x65
1242c552111SLeonard Anderweit #define AQUAERO_VIRTUAL_SENSOR_START		0x85
1253d2e9f58SAleksa Savic #define AQUAERO_CALC_VIRTUAL_SENSOR_START	0x95
1262c552111SLeonard Anderweit #define AQUAERO_FLOW_SENSORS_START		0xF9
1272c552111SLeonard Anderweit #define AQUAERO_FAN_VOLTAGE_OFFSET		0x04
1282c552111SLeonard Anderweit #define AQUAERO_FAN_CURRENT_OFFSET		0x06
1292c552111SLeonard Anderweit #define AQUAERO_FAN_POWER_OFFSET		0x08
1302c552111SLeonard Anderweit #define AQUAERO_FAN_SPEED_OFFSET		0x00
1312c552111SLeonard Anderweit static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
1322c552111SLeonard Anderweit 
133866e630aSLeonard Anderweit /* Control report offsets for the Aquaero fan controllers */
134866e630aSLeonard Anderweit #define AQUAERO_TEMP_CTRL_OFFSET	0xdb
135bd1e92f9SLeonard Anderweit #define AQUAERO_FAN_CTRL_MIN_PWR_OFFSET	0x04
136bd1e92f9SLeonard Anderweit #define AQUAERO_FAN_CTRL_MAX_PWR_OFFSET	0x06
137bd1e92f9SLeonard Anderweit #define AQUAERO_FAN_CTRL_SRC_OFFSET	0x10
138bd1e92f9SLeonard Anderweit static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 };
139866e630aSLeonard Anderweit 
140d5d896b8SAleksa Savic /* Specs of the D5 Next pump */
141654c9735SAleksa Savic #define D5NEXT_NUM_FANS			2
142654c9735SAleksa Savic #define D5NEXT_NUM_SENSORS		1
143e2769f5eSAleksa Savic #define D5NEXT_NUM_VIRTUAL_SENSORS	8
144d5d896b8SAleksa Savic #define D5NEXT_CTRL_REPORT_SIZE		0x329
145d5d896b8SAleksa Savic 
146d5d896b8SAleksa Savic /* Sensor report offsets for the D5 Next pump */
147d5d896b8SAleksa Savic #define D5NEXT_POWER_CYCLES		0x18
148d5d896b8SAleksa Savic #define D5NEXT_COOLANT_TEMP		0x57
149654c9735SAleksa Savic #define D5NEXT_PUMP_OFFSET		0x6c
150654c9735SAleksa Savic #define D5NEXT_FAN_OFFSET		0x5f
151654c9735SAleksa Savic #define D5NEXT_5V_VOLTAGE		0x39
152f4caa262SAleksa Savic #define D5NEXT_12V_VOLTAGE		0x37
153d5d896b8SAleksa Savic #define D5NEXT_VIRTUAL_SENSORS_START	0x3f
1541ed5036bSLeonard Anderweit static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
1550e35f63fSAleksa Savic 
156d5d896b8SAleksa Savic /* Control report offsets for the D5 Next pump */
157d5d896b8SAleksa Savic #define D5NEXT_TEMP_CTRL_OFFSET		0x2D	/* Temperature sensor offsets location */
158d5d896b8SAleksa Savic static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 };	/* Pump and fan speed (from 0-100%) */
15909e89309SAleksa Savic 
1607505dab7SAleksa Savic /* Specs of the Aquastream Ultimate pump */
1617505dab7SAleksa Savic /* Pump does not follow the standard structure, so only consider the fan */
1627505dab7SAleksa Savic #define AQUASTREAMULT_NUM_FANS		1
1637505dab7SAleksa Savic #define AQUASTREAMULT_NUM_SENSORS	2
1647505dab7SAleksa Savic 
1657505dab7SAleksa Savic /* Sensor report offsets for the Aquastream Ultimate pump */
1667505dab7SAleksa Savic #define AQUASTREAMULT_SENSOR_START		0x2D
1677505dab7SAleksa Savic #define AQUASTREAMULT_PUMP_OFFSET		0x51
1687505dab7SAleksa Savic #define AQUASTREAMULT_PUMP_VOLTAGE		0x3D
1697505dab7SAleksa Savic #define AQUASTREAMULT_PUMP_CURRENT		0x53
1707505dab7SAleksa Savic #define AQUASTREAMULT_PUMP_POWER		0x55
1717505dab7SAleksa Savic #define AQUASTREAMULT_FAN_OFFSET		0x41
1727505dab7SAleksa Savic #define AQUASTREAMULT_PRESSURE_OFFSET		0x57
1737505dab7SAleksa Savic #define AQUASTREAMULT_FLOW_SENSOR_OFFSET	0x37
1747505dab7SAleksa Savic #define AQUASTREAMULT_FAN_VOLTAGE_OFFSET	0x02
1757505dab7SAleksa Savic #define AQUASTREAMULT_FAN_CURRENT_OFFSET	0x00
1767505dab7SAleksa Savic #define AQUASTREAMULT_FAN_POWER_OFFSET		0x04
1777505dab7SAleksa Savic #define AQUASTREAMULT_FAN_SPEED_OFFSET		0x06
1787505dab7SAleksa Savic static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
1797505dab7SAleksa Savic 
180d5d896b8SAleksa Savic /* Spec and sensor report offset for the Farbwerk RGB controller */
181229b159cSJack Doan #define FARBWERK_NUM_SENSORS		4
182229b159cSJack Doan #define FARBWERK_SENSOR_START		0x2f
183229b159cSJack Doan 
184d5d896b8SAleksa Savic /* Specs of the Farbwerk 360 RGB controller */
1852fd3eec1SAleksa Savic #define FARBWERK360_NUM_SENSORS			4
186e2769f5eSAleksa Savic #define FARBWERK360_NUM_VIRTUAL_SENSORS		16
187662d20b3SAleksa Savic #define FARBWERK360_CTRL_REPORT_SIZE		0x682
188d5d896b8SAleksa Savic 
189d5d896b8SAleksa Savic /* Sensor report offsets for the Farbwerk 360 */
190d5d896b8SAleksa Savic #define FARBWERK360_SENSOR_START		0x32
191d5d896b8SAleksa Savic #define FARBWERK360_VIRTUAL_SENSORS_START	0x3a
192d5d896b8SAleksa Savic 
193d5d896b8SAleksa Savic /* Control report offsets for the Farbwerk 360 */
194662d20b3SAleksa Savic #define FARBWERK360_TEMP_CTRL_OFFSET		0x8
1950e35f63fSAleksa Savic 
196d5d896b8SAleksa Savic /* Specs of the Octo fan controller */
197752b9279SAleksa Savic #define OCTO_NUM_FANS			8
198752b9279SAleksa Savic #define OCTO_NUM_SENSORS		4
199e2769f5eSAleksa Savic #define OCTO_NUM_VIRTUAL_SENSORS	16
200752b9279SAleksa Savic #define OCTO_CTRL_REPORT_SIZE		0x65F
201d5d896b8SAleksa Savic 
202d5d896b8SAleksa Savic /* Sensor report offsets for the Octo */
203d5d896b8SAleksa Savic #define OCTO_POWER_CYCLES		0x18
204d5d896b8SAleksa Savic #define OCTO_SENSOR_START		0x3D
205d5d896b8SAleksa Savic #define OCTO_VIRTUAL_SENSORS_START	0x45
2061ed5036bSLeonard Anderweit static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
207752b9279SAleksa Savic 
208d5d896b8SAleksa Savic /* Control report offsets for the Octo */
209d5d896b8SAleksa Savic #define OCTO_TEMP_CTRL_OFFSET		0xA
210d5d896b8SAleksa Savic /* Fan speed offsets (0-100%) */
211752b9279SAleksa Savic static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0x259, 0x2AE };
212752b9279SAleksa Savic 
213d5d896b8SAleksa Savic /* Specs of Quadro fan controller */
214cdbe34daSAleksa Savic #define QUADRO_NUM_FANS			4
215cdbe34daSAleksa Savic #define QUADRO_NUM_SENSORS		4
216e2769f5eSAleksa Savic #define QUADRO_NUM_VIRTUAL_SENSORS	16
217a2ba7ee2SLeonard Anderweit #define QUADRO_NUM_FLOW_SENSORS		1
218cdbe34daSAleksa Savic #define QUADRO_CTRL_REPORT_SIZE		0x3c1
219d5d896b8SAleksa Savic 
220d5d896b8SAleksa Savic /* Sensor report offsets for the Quadro */
221d5d896b8SAleksa Savic #define QUADRO_POWER_CYCLES		0x18
222d5d896b8SAleksa Savic #define QUADRO_SENSOR_START		0x34
223d5d896b8SAleksa Savic #define QUADRO_VIRTUAL_SENSORS_START	0x3c
224cdbe34daSAleksa Savic #define QUADRO_FLOW_SENSOR_OFFSET	0x6e
2251ed5036bSLeonard Anderweit static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
226cdbe34daSAleksa Savic 
227d5d896b8SAleksa Savic /* Control report offsets for the Quadro */
228d5d896b8SAleksa Savic #define QUADRO_TEMP_CTRL_OFFSET		0xA
2296ff838f2SAleksa Savic #define QUADRO_FLOW_PULSES_CTRL_OFFSET	0x6
230d5d896b8SAleksa Savic static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed offsets (0-100%) */
231cdbe34daSAleksa Savic 
232d5d896b8SAleksa Savic /* Specs of High Flow Next flow sensor */
233aed80bb9SAleksa Savic #define HIGHFLOWNEXT_NUM_SENSORS	2
234a2ba7ee2SLeonard Anderweit #define HIGHFLOWNEXT_NUM_FLOW_SENSORS	1
235d5d896b8SAleksa Savic 
236d5d896b8SAleksa Savic /* Sensor report offsets for the High Flow Next */
237aed80bb9SAleksa Savic #define HIGHFLOWNEXT_SENSOR_START	85
238aed80bb9SAleksa Savic #define HIGHFLOWNEXT_FLOW		81
239aed80bb9SAleksa Savic #define HIGHFLOWNEXT_WATER_QUALITY	89
240aed80bb9SAleksa Savic #define HIGHFLOWNEXT_POWER		91
241aed80bb9SAleksa Savic #define HIGHFLOWNEXT_CONDUCTIVITY	95
242aed80bb9SAleksa Savic #define HIGHFLOWNEXT_5V_VOLTAGE		97
243aed80bb9SAleksa Savic #define HIGHFLOWNEXT_5V_VOLTAGE_USB	99
244aed80bb9SAleksa Savic 
245b3d3be6cSAleksa Savic /* Specs of the Leakshield */
246b3d3be6cSAleksa Savic #define LEAKSHIELD_NUM_SENSORS		2
247b3d3be6cSAleksa Savic 
248b3d3be6cSAleksa Savic /* Sensor report offsets for Leakshield */
249b3d3be6cSAleksa Savic #define LEAKSHIELD_PRESSURE_ADJUSTED	285
250b3d3be6cSAleksa Savic #define LEAKSHIELD_TEMPERATURE_1	265
251b3d3be6cSAleksa Savic #define LEAKSHIELD_TEMPERATURE_2	287
252b3d3be6cSAleksa Savic #define LEAKSHIELD_PRESSURE_MIN		291
253b3d3be6cSAleksa Savic #define LEAKSHIELD_PRESSURE_TARGET	293
254b3d3be6cSAleksa Savic #define LEAKSHIELD_PRESSURE_MAX		295
255b3d3be6cSAleksa Savic #define LEAKSHIELD_PUMP_RPM_IN		101
256b3d3be6cSAleksa Savic #define LEAKSHIELD_FLOW_IN		111
257b3d3be6cSAleksa Savic #define LEAKSHIELD_RESERVOIR_VOLUME	313
258b3d3be6cSAleksa Savic #define LEAKSHIELD_RESERVOIR_FILLED	311
259b3d3be6cSAleksa Savic 
26019692f17SAleksa Savic /* Specs of the Aquastream XT pump */
26119692f17SAleksa Savic #define AQUASTREAMXT_SERIAL_START		0x3a
26219692f17SAleksa Savic #define AQUASTREAMXT_FIRMWARE_VERSION		0x32
26319692f17SAleksa Savic #define AQUASTREAMXT_NUM_FANS			2
26419692f17SAleksa Savic #define AQUASTREAMXT_NUM_SENSORS		3
26519692f17SAleksa Savic #define AQUASTREAMXT_FAN_STOPPED		0x4
26619692f17SAleksa Savic #define AQUASTREAMXT_PUMP_CONVERSION_CONST	45000000
26719692f17SAleksa Savic #define AQUASTREAMXT_FAN_CONVERSION_CONST	5646000
26819692f17SAleksa Savic #define AQUASTREAMXT_SENSOR_REPORT_SIZE		0x42
26919692f17SAleksa Savic 
27019692f17SAleksa Savic /* Sensor report offsets and info for Aquastream XT */
27119692f17SAleksa Savic #define AQUASTREAMXT_SENSOR_START		0xd
27219692f17SAleksa Savic #define AQUASTREAMXT_FAN_VOLTAGE_OFFSET		0x7
27319692f17SAleksa Savic #define AQUASTREAMXT_FAN_STATUS_OFFSET		0x1d
27419692f17SAleksa Savic #define AQUASTREAMXT_PUMP_VOLTAGE_OFFSET	0x9
27519692f17SAleksa Savic #define AQUASTREAMXT_PUMP_CURR_OFFSET		0xb
27619692f17SAleksa Savic static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b };
27719692f17SAleksa Savic 
278e0f6c370SAleksa Savic /* Specs of the Poweradjust 3 */
279e0f6c370SAleksa Savic #define POWERADJUST3_NUM_SENSORS	1
280e0f6c370SAleksa Savic #define POWERADJUST3_SENSOR_REPORT_SIZE	0x32
281e0f6c370SAleksa Savic 
282e0f6c370SAleksa Savic /* Sensor report offsets for the Poweradjust 3 */
283e0f6c370SAleksa Savic #define POWERADJUST3_SENSOR_START	0x03
284e0f6c370SAleksa Savic 
2852fd3eec1SAleksa Savic /* Labels for D5 Next */
286752b9279SAleksa Savic static const char *const label_d5next_temp[] = {
287752b9279SAleksa Savic 	"Coolant temp"
288752b9279SAleksa Savic };
2890e35f63fSAleksa Savic 
2902fd3eec1SAleksa Savic static const char *const label_d5next_speeds[] = {
2912fd3eec1SAleksa Savic 	"Pump speed",
2922fd3eec1SAleksa Savic 	"Fan speed"
2930e35f63fSAleksa Savic };
2940e35f63fSAleksa Savic 
2952fd3eec1SAleksa Savic static const char *const label_d5next_power[] = {
2962fd3eec1SAleksa Savic 	"Pump power",
2972fd3eec1SAleksa Savic 	"Fan power"
2980e35f63fSAleksa Savic };
2990e35f63fSAleksa Savic 
3002fd3eec1SAleksa Savic static const char *const label_d5next_voltages[] = {
3012fd3eec1SAleksa Savic 	"Pump voltage",
3022fd3eec1SAleksa Savic 	"Fan voltage",
303f4caa262SAleksa Savic 	"+5V voltage",
304f4caa262SAleksa Savic 	"+12V voltage"
3050e35f63fSAleksa Savic };
3060e35f63fSAleksa Savic 
3072fd3eec1SAleksa Savic static const char *const label_d5next_current[] = {
3082fd3eec1SAleksa Savic 	"Pump current",
3092fd3eec1SAleksa Savic 	"Fan current"
3100e35f63fSAleksa Savic };
3110e35f63fSAleksa Savic 
3122c552111SLeonard Anderweit /* Labels for Aquaero, Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
3132fd3eec1SAleksa Savic static const char *const label_temp_sensors[] = {
3142fd3eec1SAleksa Savic 	"Sensor 1",
3152fd3eec1SAleksa Savic 	"Sensor 2",
3162fd3eec1SAleksa Savic 	"Sensor 3",
3172c552111SLeonard Anderweit 	"Sensor 4",
3182c552111SLeonard Anderweit 	"Sensor 5",
3192c552111SLeonard Anderweit 	"Sensor 6",
3202c552111SLeonard Anderweit 	"Sensor 7",
3212c552111SLeonard Anderweit 	"Sensor 8"
3222fd3eec1SAleksa Savic };
3232fd3eec1SAleksa Savic 
324e2769f5eSAleksa Savic static const char *const label_virtual_temp_sensors[] = {
325e2769f5eSAleksa Savic 	"Virtual sensor 1",
326e2769f5eSAleksa Savic 	"Virtual sensor 2",
327e2769f5eSAleksa Savic 	"Virtual sensor 3",
328e2769f5eSAleksa Savic 	"Virtual sensor 4",
329e2769f5eSAleksa Savic 	"Virtual sensor 5",
330e2769f5eSAleksa Savic 	"Virtual sensor 6",
331e2769f5eSAleksa Savic 	"Virtual sensor 7",
332e2769f5eSAleksa Savic 	"Virtual sensor 8",
333e2769f5eSAleksa Savic 	"Virtual sensor 9",
334e2769f5eSAleksa Savic 	"Virtual sensor 10",
335e2769f5eSAleksa Savic 	"Virtual sensor 11",
336e2769f5eSAleksa Savic 	"Virtual sensor 12",
337e2769f5eSAleksa Savic 	"Virtual sensor 13",
338e2769f5eSAleksa Savic 	"Virtual sensor 14",
339e2769f5eSAleksa Savic 	"Virtual sensor 15",
340e2769f5eSAleksa Savic 	"Virtual sensor 16",
341e2769f5eSAleksa Savic };
342e2769f5eSAleksa Savic 
3433d2e9f58SAleksa Savic static const char *const label_aquaero_calc_temp_sensors[] = {
3443d2e9f58SAleksa Savic 	"Calc. virtual sensor 1",
3453d2e9f58SAleksa Savic 	"Calc. virtual sensor 2",
3463d2e9f58SAleksa Savic 	"Calc. virtual sensor 3",
3473d2e9f58SAleksa Savic 	"Calc. virtual sensor 4"
3483d2e9f58SAleksa Savic };
3493d2e9f58SAleksa Savic 
350cdbe34daSAleksa Savic /* Labels for Octo and Quadro (except speed) */
351752b9279SAleksa Savic static const char *const label_fan_speed[] = {
352752b9279SAleksa Savic 	"Fan 1 speed",
353752b9279SAleksa Savic 	"Fan 2 speed",
354752b9279SAleksa Savic 	"Fan 3 speed",
355752b9279SAleksa Savic 	"Fan 4 speed",
356752b9279SAleksa Savic 	"Fan 5 speed",
357752b9279SAleksa Savic 	"Fan 6 speed",
358752b9279SAleksa Savic 	"Fan 7 speed",
359752b9279SAleksa Savic 	"Fan 8 speed"
360752b9279SAleksa Savic };
361752b9279SAleksa Savic 
362752b9279SAleksa Savic static const char *const label_fan_power[] = {
363752b9279SAleksa Savic 	"Fan 1 power",
364752b9279SAleksa Savic 	"Fan 2 power",
365752b9279SAleksa Savic 	"Fan 3 power",
366752b9279SAleksa Savic 	"Fan 4 power",
367752b9279SAleksa Savic 	"Fan 5 power",
368752b9279SAleksa Savic 	"Fan 6 power",
369752b9279SAleksa Savic 	"Fan 7 power",
370752b9279SAleksa Savic 	"Fan 8 power"
371752b9279SAleksa Savic };
372752b9279SAleksa Savic 
373752b9279SAleksa Savic static const char *const label_fan_voltage[] = {
374752b9279SAleksa Savic 	"Fan 1 voltage",
375752b9279SAleksa Savic 	"Fan 2 voltage",
376752b9279SAleksa Savic 	"Fan 3 voltage",
377752b9279SAleksa Savic 	"Fan 4 voltage",
378752b9279SAleksa Savic 	"Fan 5 voltage",
379752b9279SAleksa Savic 	"Fan 6 voltage",
380752b9279SAleksa Savic 	"Fan 7 voltage",
381752b9279SAleksa Savic 	"Fan 8 voltage"
382752b9279SAleksa Savic };
383752b9279SAleksa Savic 
384752b9279SAleksa Savic static const char *const label_fan_current[] = {
385752b9279SAleksa Savic 	"Fan 1 current",
386752b9279SAleksa Savic 	"Fan 2 current",
387752b9279SAleksa Savic 	"Fan 3 current",
388752b9279SAleksa Savic 	"Fan 4 current",
389752b9279SAleksa Savic 	"Fan 5 current",
390752b9279SAleksa Savic 	"Fan 6 current",
391752b9279SAleksa Savic 	"Fan 7 current",
392752b9279SAleksa Savic 	"Fan 8 current"
393752b9279SAleksa Savic };
394752b9279SAleksa Savic 
395cdbe34daSAleksa Savic /* Labels for Quadro fan speeds */
396cdbe34daSAleksa Savic static const char *const label_quadro_speeds[] = {
397cdbe34daSAleksa Savic 	"Fan 1 speed",
398cdbe34daSAleksa Savic 	"Fan 2 speed",
399cdbe34daSAleksa Savic 	"Fan 3 speed",
400cdbe34daSAleksa Savic 	"Fan 4 speed",
401cdbe34daSAleksa Savic 	"Flow speed [dL/h]"
402cdbe34daSAleksa Savic };
403cdbe34daSAleksa Savic 
4042c552111SLeonard Anderweit /* Labels for Aquaero fan speeds */
4052c552111SLeonard Anderweit static const char *const label_aquaero_speeds[] = {
4062c552111SLeonard Anderweit 	"Fan 1 speed",
4072c552111SLeonard Anderweit 	"Fan 2 speed",
4082c552111SLeonard Anderweit 	"Fan 3 speed",
4092c552111SLeonard Anderweit 	"Fan 4 speed",
4102c552111SLeonard Anderweit 	"Flow sensor 1 [dL/h]",
4112c552111SLeonard Anderweit 	"Flow sensor 2 [dL/h]"
4122c552111SLeonard Anderweit };
4132c552111SLeonard Anderweit 
414aed80bb9SAleksa Savic /* Labels for High Flow Next */
415aed80bb9SAleksa Savic static const char *const label_highflownext_temp_sensors[] = {
416aed80bb9SAleksa Savic 	"Coolant temp",
417aed80bb9SAleksa Savic 	"External sensor"
418aed80bb9SAleksa Savic };
419aed80bb9SAleksa Savic 
420aed80bb9SAleksa Savic static const char *const label_highflownext_fan_speed[] = {
421aed80bb9SAleksa Savic 	"Flow [dL/h]",
422aed80bb9SAleksa Savic 	"Water quality [%]",
423aed80bb9SAleksa Savic 	"Conductivity [nS/cm]",
424aed80bb9SAleksa Savic };
425aed80bb9SAleksa Savic 
426aed80bb9SAleksa Savic static const char *const label_highflownext_power[] = {
427aed80bb9SAleksa Savic 	"Dissipated power",
428aed80bb9SAleksa Savic };
429aed80bb9SAleksa Savic 
430aed80bb9SAleksa Savic static const char *const label_highflownext_voltage[] = {
431aed80bb9SAleksa Savic 	"+5V voltage",
432aed80bb9SAleksa Savic 	"+5V USB voltage"
433aed80bb9SAleksa Savic };
434aed80bb9SAleksa Savic 
435b3d3be6cSAleksa Savic /* Labels for Leakshield */
436b3d3be6cSAleksa Savic static const char *const label_leakshield_temp_sensors[] = {
437b3d3be6cSAleksa Savic 	"Temperature 1",
438b3d3be6cSAleksa Savic 	"Temperature 2"
439b3d3be6cSAleksa Savic };
440b3d3be6cSAleksa Savic 
441b3d3be6cSAleksa Savic static const char *const label_leakshield_fan_speed[] = {
442b3d3be6cSAleksa Savic 	"Pressure [ubar]",
443b3d3be6cSAleksa Savic 	"User-Provided Pump Speed",
444b3d3be6cSAleksa Savic 	"User-Provided Flow [dL/h]",
445b3d3be6cSAleksa Savic 	"Reservoir Volume [ml]",
446b3d3be6cSAleksa Savic 	"Reservoir Filled [ml]",
447b3d3be6cSAleksa Savic };
448b3d3be6cSAleksa Savic 
44919692f17SAleksa Savic /* Labels for Aquastream XT */
45019692f17SAleksa Savic static const char *const label_aquastreamxt_temp_sensors[] = {
45119692f17SAleksa Savic 	"Fan IC temp",
45219692f17SAleksa Savic 	"External sensor",
45319692f17SAleksa Savic 	"Coolant temp"
45419692f17SAleksa Savic };
45519692f17SAleksa Savic 
4567505dab7SAleksa Savic /* Labels for Aquastream Ultimate */
4577505dab7SAleksa Savic static const char *const label_aquastreamult_temp[] = {
4587505dab7SAleksa Savic 	"Coolant temp",
4597505dab7SAleksa Savic 	"External temp"
4607505dab7SAleksa Savic };
4617505dab7SAleksa Savic 
4627505dab7SAleksa Savic static const char *const label_aquastreamult_speeds[] = {
4637505dab7SAleksa Savic 	"Fan speed",
4647505dab7SAleksa Savic 	"Pump speed",
4657505dab7SAleksa Savic 	"Pressure [mbar]",
4667505dab7SAleksa Savic 	"Flow speed [dL/h]"
4677505dab7SAleksa Savic };
4687505dab7SAleksa Savic 
4697505dab7SAleksa Savic static const char *const label_aquastreamult_power[] = {
4707505dab7SAleksa Savic 	"Fan power",
4717505dab7SAleksa Savic 	"Pump power"
4727505dab7SAleksa Savic };
4737505dab7SAleksa Savic 
4747505dab7SAleksa Savic static const char *const label_aquastreamult_voltages[] = {
4757505dab7SAleksa Savic 	"Fan voltage",
4767505dab7SAleksa Savic 	"Pump voltage"
4777505dab7SAleksa Savic };
4787505dab7SAleksa Savic 
4797505dab7SAleksa Savic static const char *const label_aquastreamult_current[] = {
4807505dab7SAleksa Savic 	"Fan current",
4817505dab7SAleksa Savic 	"Pump current"
4827505dab7SAleksa Savic };
4837505dab7SAleksa Savic 
484e0f6c370SAleksa Savic /* Labels for Poweradjust 3 */
485e0f6c370SAleksa Savic static const char *const label_poweradjust3_temp_sensors[] = {
486e0f6c370SAleksa Savic 	"External sensor"
487e0f6c370SAleksa Savic };
488e0f6c370SAleksa Savic 
489249c7521SLeonard Anderweit struct aqc_fan_structure_offsets {
490249c7521SLeonard Anderweit 	u8 voltage;
491249c7521SLeonard Anderweit 	u8 curr;
492249c7521SLeonard Anderweit 	u8 power;
493249c7521SLeonard Anderweit 	u8 speed;
494249c7521SLeonard Anderweit };
495249c7521SLeonard Anderweit 
4962c552111SLeonard Anderweit /* Fan structure offsets for Aquaero */
4972c552111SLeonard Anderweit static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = {
4982c552111SLeonard Anderweit 	.voltage = AQUAERO_FAN_VOLTAGE_OFFSET,
4992c552111SLeonard Anderweit 	.curr = AQUAERO_FAN_CURRENT_OFFSET,
5002c552111SLeonard Anderweit 	.power = AQUAERO_FAN_POWER_OFFSET,
5012c552111SLeonard Anderweit 	.speed = AQUAERO_FAN_SPEED_OFFSET
5022c552111SLeonard Anderweit };
5032c552111SLeonard Anderweit 
5047505dab7SAleksa Savic /* Fan structure offsets for Aquastream Ultimate */
5057505dab7SAleksa Savic static struct aqc_fan_structure_offsets aqc_aquastreamult_fan_structure = {
5067505dab7SAleksa Savic 	.voltage = AQUASTREAMULT_FAN_VOLTAGE_OFFSET,
5077505dab7SAleksa Savic 	.curr = AQUASTREAMULT_FAN_CURRENT_OFFSET,
5087505dab7SAleksa Savic 	.power = AQUASTREAMULT_FAN_POWER_OFFSET,
5097505dab7SAleksa Savic 	.speed = AQUASTREAMULT_FAN_SPEED_OFFSET
5107505dab7SAleksa Savic };
5117505dab7SAleksa Savic 
5127505dab7SAleksa Savic /* Fan structure offsets for all devices except those above */
513249c7521SLeonard Anderweit static struct aqc_fan_structure_offsets aqc_general_fan_structure = {
514249c7521SLeonard Anderweit 	.voltage = AQC_FAN_VOLTAGE_OFFSET,
515249c7521SLeonard Anderweit 	.curr = AQC_FAN_CURRENT_OFFSET,
516249c7521SLeonard Anderweit 	.power = AQC_FAN_POWER_OFFSET,
517249c7521SLeonard Anderweit 	.speed = AQC_FAN_SPEED_OFFSET
518249c7521SLeonard Anderweit };
519249c7521SLeonard Anderweit 
5202fd3eec1SAleksa Savic struct aqc_data {
5210e35f63fSAleksa Savic 	struct hid_device *hdev;
5220e35f63fSAleksa Savic 	struct device *hwmon_dev;
5230e35f63fSAleksa Savic 	struct dentry *debugfs;
524752b9279SAleksa Savic 	struct mutex mutex;	/* Used for locking access when reading and writing PWM values */
5252fd3eec1SAleksa Savic 	enum kinds kind;
5262fd3eec1SAleksa Savic 	const char *name;
5272fd3eec1SAleksa Savic 
528e0f6c370SAleksa Savic 	int status_report_id;	/* Used for legacy devices, report is stored in buffer */
529b29090baSLeonard Anderweit 	int ctrl_report_id;
530b29090baSLeonard Anderweit 	int secondary_ctrl_report_id;
531b29090baSLeonard Anderweit 	int secondary_ctrl_report_size;
532b29090baSLeonard Anderweit 	u8 *secondary_ctrl_report;
533e0f6c370SAleksa Savic 
534*56b930dcSAleksa Savic 	ktime_t last_ctrl_report_op;
535*56b930dcSAleksa Savic 	int ctrl_report_delay;	/* Delay between two ctrl report operations, in ms */
536*56b930dcSAleksa Savic 
537752b9279SAleksa Savic 	int buffer_size;
538752b9279SAleksa Savic 	u8 *buffer;
539752b9279SAleksa Savic 	int checksum_start;
540752b9279SAleksa Savic 	int checksum_length;
541752b9279SAleksa Savic 	int checksum_offset;
542752b9279SAleksa Savic 
543654c9735SAleksa Savic 	int num_fans;
5441ed5036bSLeonard Anderweit 	u16 *fan_sensor_offsets;
545654c9735SAleksa Savic 	u16 *fan_ctrl_offsets;
546654c9735SAleksa Savic 	int num_temp_sensors;
547654c9735SAleksa Savic 	int temp_sensor_start_offset;
548e2769f5eSAleksa Savic 	int num_virtual_temp_sensors;
549e2769f5eSAleksa Savic 	int virtual_temp_sensor_start_offset;
5503d2e9f58SAleksa Savic 	int num_calc_virt_temp_sensors;
5513d2e9f58SAleksa Savic 	int calc_virt_temp_sensor_start_offset;
552662d20b3SAleksa Savic 	u16 temp_ctrl_offset;
553654c9735SAleksa Savic 	u16 power_cycle_count_offset;
554a2ba7ee2SLeonard Anderweit 	int num_flow_sensors;
555a2ba7ee2SLeonard Anderweit 	u8 flow_sensors_start_offset;
5566ff838f2SAleksa Savic 	u8 flow_pulses_ctrl_offset;
557249c7521SLeonard Anderweit 	struct aqc_fan_structure_offsets *fan_structure;
558654c9735SAleksa Savic 
5592fd3eec1SAleksa Savic 	/* General info, same across all devices */
560ad2f0811SLeonard Anderweit 	u8 serial_number_start_offset;
5612fd3eec1SAleksa Savic 	u32 serial_number[2];
562ad2f0811SLeonard Anderweit 	u8 firmware_version_offset;
5632fd3eec1SAleksa Savic 	u16 firmware_version;
5642fd3eec1SAleksa Savic 
565654c9735SAleksa Savic 	/* How many times the device was powered on, if available */
5662fd3eec1SAleksa Savic 	u32 power_cycles;
5672fd3eec1SAleksa Savic 
5682fd3eec1SAleksa Savic 	/* Sensor values */
5693d2e9f58SAleksa Savic 	s32 temp_input[20];	/* Max 4 physical and 16 virtual or 8 physical and 12 virtual */
570b3d3be6cSAleksa Savic 	s32 speed_input[8];
571b3d3be6cSAleksa Savic 	u32 speed_input_min[1];
572b3d3be6cSAleksa Savic 	u32 speed_input_target[1];
573b3d3be6cSAleksa Savic 	u32 speed_input_max[1];
574752b9279SAleksa Savic 	u32 power_input[8];
575752b9279SAleksa Savic 	u16 voltage_input[8];
576752b9279SAleksa Savic 	u16 current_input[8];
577752b9279SAleksa Savic 
578752b9279SAleksa Savic 	/* Label values */
579752b9279SAleksa Savic 	const char *const *temp_label;
580e2769f5eSAleksa Savic 	const char *const *virtual_temp_label;
5813d2e9f58SAleksa Savic 	const char *const *calc_virt_temp_label;	/* For Aquaero */
582752b9279SAleksa Savic 	const char *const *speed_label;
583752b9279SAleksa Savic 	const char *const *power_label;
584752b9279SAleksa Savic 	const char *const *voltage_label;
585752b9279SAleksa Savic 	const char *const *current_label;
5862fd3eec1SAleksa Savic 
5870e35f63fSAleksa Savic 	unsigned long updated;
5880e35f63fSAleksa Savic };
5890e35f63fSAleksa Savic 
590752b9279SAleksa Savic /* Converts from centi-percent */
aqc_percent_to_pwm(u16 val)591752b9279SAleksa Savic static int aqc_percent_to_pwm(u16 val)
592752b9279SAleksa Savic {
593752b9279SAleksa Savic 	return DIV_ROUND_CLOSEST(val * 255, 100 * 100);
594752b9279SAleksa Savic }
595752b9279SAleksa Savic 
596752b9279SAleksa Savic /* Converts to centi-percent */
aqc_pwm_to_percent(long val)597752b9279SAleksa Savic static int aqc_pwm_to_percent(long val)
598752b9279SAleksa Savic {
599752b9279SAleksa Savic 	if (val < 0 || val > 255)
600752b9279SAleksa Savic 		return -EINVAL;
601752b9279SAleksa Savic 
602752b9279SAleksa Savic 	return DIV_ROUND_CLOSEST(val * 100 * 100, 255);
603752b9279SAleksa Savic }
604752b9279SAleksa Savic 
60519692f17SAleksa Savic /* Converts raw value for Aquastream XT pump speed to RPM */
aqc_aquastreamxt_convert_pump_rpm(u16 val)60619692f17SAleksa Savic static int aqc_aquastreamxt_convert_pump_rpm(u16 val)
60719692f17SAleksa Savic {
60819692f17SAleksa Savic 	if (val > 0)
60919692f17SAleksa Savic 		return DIV_ROUND_CLOSEST(AQUASTREAMXT_PUMP_CONVERSION_CONST, val);
61019692f17SAleksa Savic 	return 0;
61119692f17SAleksa Savic }
61219692f17SAleksa Savic 
61319692f17SAleksa Savic /* Converts raw value for Aquastream XT fan speed to RPM */
aqc_aquastreamxt_convert_fan_rpm(u16 val)61419692f17SAleksa Savic static int aqc_aquastreamxt_convert_fan_rpm(u16 val)
61519692f17SAleksa Savic {
61619692f17SAleksa Savic 	if (val > 0)
61719692f17SAleksa Savic 		return DIV_ROUND_CLOSEST(AQUASTREAMXT_FAN_CONVERSION_CONST, val);
61819692f17SAleksa Savic 	return 0;
61919692f17SAleksa Savic }
62019692f17SAleksa Savic 
aqc_delay_ctrl_report(struct aqc_data * priv)621*56b930dcSAleksa Savic static void aqc_delay_ctrl_report(struct aqc_data *priv)
622*56b930dcSAleksa Savic {
623*56b930dcSAleksa Savic 	/*
624*56b930dcSAleksa Savic 	 * If previous read or write is too close to this one, delay the current operation
625*56b930dcSAleksa Savic 	 * to give the device enough time to process the previous one.
626*56b930dcSAleksa Savic 	 */
627*56b930dcSAleksa Savic 	if (priv->ctrl_report_delay) {
628*56b930dcSAleksa Savic 		s64 delta = ktime_ms_delta(ktime_get(), priv->last_ctrl_report_op);
629*56b930dcSAleksa Savic 
630*56b930dcSAleksa Savic 		if (delta < priv->ctrl_report_delay)
631*56b930dcSAleksa Savic 			msleep(priv->ctrl_report_delay - delta);
632*56b930dcSAleksa Savic 	}
633*56b930dcSAleksa Savic }
634*56b930dcSAleksa Savic 
635752b9279SAleksa Savic /* Expects the mutex to be locked */
aqc_get_ctrl_data(struct aqc_data * priv)636752b9279SAleksa Savic static int aqc_get_ctrl_data(struct aqc_data *priv)
637752b9279SAleksa Savic {
638752b9279SAleksa Savic 	int ret;
639752b9279SAleksa Savic 
640*56b930dcSAleksa Savic 	aqc_delay_ctrl_report(priv);
641*56b930dcSAleksa Savic 
642752b9279SAleksa Savic 	memset(priv->buffer, 0x00, priv->buffer_size);
643b29090baSLeonard Anderweit 	ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
644752b9279SAleksa Savic 				 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
645752b9279SAleksa Savic 	if (ret < 0)
646752b9279SAleksa Savic 		ret = -ENODATA;
647752b9279SAleksa Savic 
648*56b930dcSAleksa Savic 	priv->last_ctrl_report_op = ktime_get();
649*56b930dcSAleksa Savic 
650752b9279SAleksa Savic 	return ret;
651752b9279SAleksa Savic }
652752b9279SAleksa Savic 
653752b9279SAleksa Savic /* Expects the mutex to be locked */
aqc_send_ctrl_data(struct aqc_data * priv)654752b9279SAleksa Savic static int aqc_send_ctrl_data(struct aqc_data *priv)
655752b9279SAleksa Savic {
656752b9279SAleksa Savic 	int ret;
657752b9279SAleksa Savic 	u16 checksum;
658752b9279SAleksa Savic 
659*56b930dcSAleksa Savic 	aqc_delay_ctrl_report(priv);
660*56b930dcSAleksa Savic 
6616c83ccb1SLeonard Anderweit 	/* Checksum is not needed for Aquaero */
6626c83ccb1SLeonard Anderweit 	if (priv->kind != aquaero) {
663752b9279SAleksa Savic 		/* Init and xorout value for CRC-16/USB is 0xffff */
6646c83ccb1SLeonard Anderweit 		checksum = crc16(0xffff, priv->buffer + priv->checksum_start,
6656c83ccb1SLeonard Anderweit 				 priv->checksum_length);
666752b9279SAleksa Savic 		checksum ^= 0xffff;
667752b9279SAleksa Savic 
668752b9279SAleksa Savic 		/* Place the new checksum at the end of the report */
669752b9279SAleksa Savic 		put_unaligned_be16(checksum, priv->buffer + priv->checksum_offset);
6706c83ccb1SLeonard Anderweit 	}
671752b9279SAleksa Savic 
672752b9279SAleksa Savic 	/* Send the patched up report back to the device */
673b29090baSLeonard Anderweit 	ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
674752b9279SAleksa Savic 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
675752b9279SAleksa Savic 	if (ret < 0)
676*56b930dcSAleksa Savic 		goto record_access_and_ret;
677752b9279SAleksa Savic 
678752b9279SAleksa Savic 	/* The official software sends this report after every change, so do it here as well */
679b29090baSLeonard Anderweit 	ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id,
680b29090baSLeonard Anderweit 				 priv->secondary_ctrl_report, priv->secondary_ctrl_report_size,
681b29090baSLeonard Anderweit 				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
682*56b930dcSAleksa Savic 
683*56b930dcSAleksa Savic record_access_and_ret:
684*56b930dcSAleksa Savic 	priv->last_ctrl_report_op = ktime_get();
685*56b930dcSAleksa Savic 
686752b9279SAleksa Savic 	return ret;
687752b9279SAleksa Savic }
688752b9279SAleksa Savic 
689662d20b3SAleksa Savic /* Refreshes the control buffer and stores value at offset in val */
aqc_get_ctrl_val(struct aqc_data * priv,int offset,long * val,int type)690d0450fc1SLeonard Anderweit static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int type)
691752b9279SAleksa Savic {
692752b9279SAleksa Savic 	int ret;
693752b9279SAleksa Savic 
694752b9279SAleksa Savic 	mutex_lock(&priv->mutex);
695752b9279SAleksa Savic 
696752b9279SAleksa Savic 	ret = aqc_get_ctrl_data(priv);
697752b9279SAleksa Savic 	if (ret < 0)
698752b9279SAleksa Savic 		goto unlock_and_return;
699752b9279SAleksa Savic 
700d0450fc1SLeonard Anderweit 	switch (type) {
701d0450fc1SLeonard Anderweit 	case AQC_BE16:
702662d20b3SAleksa Savic 		*val = (s16)get_unaligned_be16(priv->buffer + offset);
703d0450fc1SLeonard Anderweit 		break;
704d0450fc1SLeonard Anderweit 	case AQC_8:
705d0450fc1SLeonard Anderweit 		*val = priv->buffer[offset];
706d0450fc1SLeonard Anderweit 		break;
707d0450fc1SLeonard Anderweit 	default:
708d0450fc1SLeonard Anderweit 		ret = -EINVAL;
709d0450fc1SLeonard Anderweit 	}
710752b9279SAleksa Savic 
711752b9279SAleksa Savic unlock_and_return:
712752b9279SAleksa Savic 	mutex_unlock(&priv->mutex);
713752b9279SAleksa Savic 	return ret;
714752b9279SAleksa Savic }
715752b9279SAleksa Savic 
aqc_set_ctrl_vals(struct aqc_data * priv,int * offsets,long * vals,int * types,int len)7164d09d155SLeonard Anderweit static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, int *types, int len)
717752b9279SAleksa Savic {
7184d09d155SLeonard Anderweit 	int ret, i;
719752b9279SAleksa Savic 
720752b9279SAleksa Savic 	mutex_lock(&priv->mutex);
721752b9279SAleksa Savic 
722752b9279SAleksa Savic 	ret = aqc_get_ctrl_data(priv);
723752b9279SAleksa Savic 	if (ret < 0)
724752b9279SAleksa Savic 		goto unlock_and_return;
725752b9279SAleksa Savic 
7264d09d155SLeonard Anderweit 	for (i = 0; i < len; i++) {
7274d09d155SLeonard Anderweit 		switch (types[i]) {
728d0450fc1SLeonard Anderweit 		case AQC_BE16:
7294d09d155SLeonard Anderweit 			put_unaligned_be16((s16)vals[i], priv->buffer + offsets[i]);
730d0450fc1SLeonard Anderweit 			break;
731d0450fc1SLeonard Anderweit 		case AQC_8:
7324d09d155SLeonard Anderweit 			priv->buffer[offsets[i]] = (u8)vals[i];
733d0450fc1SLeonard Anderweit 			break;
734d0450fc1SLeonard Anderweit 		default:
735d0450fc1SLeonard Anderweit 			ret = -EINVAL;
736d0450fc1SLeonard Anderweit 		}
7374d09d155SLeonard Anderweit 	}
738d0450fc1SLeonard Anderweit 
739d0450fc1SLeonard Anderweit 	if (ret < 0)
740d0450fc1SLeonard Anderweit 		goto unlock_and_return;
741752b9279SAleksa Savic 
742752b9279SAleksa Savic 	ret = aqc_send_ctrl_data(priv);
743752b9279SAleksa Savic 
744752b9279SAleksa Savic unlock_and_return:
745752b9279SAleksa Savic 	mutex_unlock(&priv->mutex);
746752b9279SAleksa Savic 	return ret;
747752b9279SAleksa Savic }
748752b9279SAleksa Savic 
aqc_set_ctrl_val(struct aqc_data * priv,int offset,long val,int type)7494d09d155SLeonard Anderweit static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type)
7504d09d155SLeonard Anderweit {
7514d09d155SLeonard Anderweit 	return aqc_set_ctrl_vals(priv, &offset, &val, &type, 1);
7524d09d155SLeonard Anderweit }
7534d09d155SLeonard Anderweit 
aqc_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)754752b9279SAleksa Savic static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel)
7550e35f63fSAleksa Savic {
7562fd3eec1SAleksa Savic 	const struct aqc_data *priv = data;
7572fd3eec1SAleksa Savic 
7582fd3eec1SAleksa Savic 	switch (type) {
7592fd3eec1SAleksa Savic 	case hwmon_temp:
760662d20b3SAleksa Savic 		if (channel < priv->num_temp_sensors) {
761662d20b3SAleksa Savic 			switch (attr) {
762662d20b3SAleksa Savic 			case hwmon_temp_label:
763662d20b3SAleksa Savic 			case hwmon_temp_input:
7640e35f63fSAleksa Savic 				return 0444;
765662d20b3SAleksa Savic 			case hwmon_temp_offset:
766662d20b3SAleksa Savic 				if (priv->temp_ctrl_offset != 0)
767662d20b3SAleksa Savic 					return 0644;
768662d20b3SAleksa Savic 				break;
769662d20b3SAleksa Savic 			default:
770662d20b3SAleksa Savic 				break;
771662d20b3SAleksa Savic 			}
772662d20b3SAleksa Savic 		}
773662d20b3SAleksa Savic 
7743d2e9f58SAleksa Savic 		if (channel <
7753d2e9f58SAleksa Savic 		    priv->num_temp_sensors + priv->num_virtual_temp_sensors +
7763d2e9f58SAleksa Savic 		    priv->num_calc_virt_temp_sensors)
777662d20b3SAleksa Savic 			switch (attr) {
778662d20b3SAleksa Savic 			case hwmon_temp_label:
779662d20b3SAleksa Savic 			case hwmon_temp_input:
780662d20b3SAleksa Savic 				return 0444;
781662d20b3SAleksa Savic 			default:
782662d20b3SAleksa Savic 				break;
783662d20b3SAleksa Savic 			}
7842fd3eec1SAleksa Savic 		break;
785752b9279SAleksa Savic 	case hwmon_pwm:
786654c9735SAleksa Savic 		if (priv->fan_ctrl_offsets && channel < priv->num_fans) {
787752b9279SAleksa Savic 			switch (attr) {
788752b9279SAleksa Savic 			case hwmon_pwm_input:
789752b9279SAleksa Savic 				return 0644;
790752b9279SAleksa Savic 			default:
791752b9279SAleksa Savic 				break;
792752b9279SAleksa Savic 			}
793752b9279SAleksa Savic 		}
794752b9279SAleksa Savic 		break;
7952fd3eec1SAleksa Savic 	case hwmon_fan:
7966ff838f2SAleksa Savic 		switch (attr) {
7976ff838f2SAleksa Savic 		case hwmon_fan_input:
7986ff838f2SAleksa Savic 		case hwmon_fan_label:
799cdbe34daSAleksa Savic 			switch (priv->kind) {
8007505dab7SAleksa Savic 			case aquastreamult:
8017505dab7SAleksa Savic 				/*
8027505dab7SAleksa Savic 				 * Special case to support pump RPM, fan RPM,
8037505dab7SAleksa Savic 				 * pressure and flow sensor
8047505dab7SAleksa Savic 				 */
8057505dab7SAleksa Savic 				if (channel < 4)
8067505dab7SAleksa Savic 					return 0444;
8077505dab7SAleksa Savic 				break;
808aed80bb9SAleksa Savic 			case highflownext:
8096ff838f2SAleksa Savic 				/* Special case to support flow sensor, water quality
8106ff838f2SAleksa Savic 				 * and conductivity
8116ff838f2SAleksa Savic 				 */
812aed80bb9SAleksa Savic 				if (channel < 3)
813aed80bb9SAleksa Savic 					return 0444;
814aed80bb9SAleksa Savic 				break;
815b3d3be6cSAleksa Savic 			case leakshield:
816b3d3be6cSAleksa Savic 				/* Special case for Leakshield sensors */
817b3d3be6cSAleksa Savic 				if (channel < 5)
818b3d3be6cSAleksa Savic 					return 0444;
819b3d3be6cSAleksa Savic 				break;
8202c552111SLeonard Anderweit 			case aquaero:
821cdbe34daSAleksa Savic 			case quadro:
822a2ba7ee2SLeonard Anderweit 				/* Special case to support flow sensors */
823a2ba7ee2SLeonard Anderweit 				if (channel < priv->num_fans + priv->num_flow_sensors)
824cdbe34daSAleksa Savic 					return 0444;
825cdbe34daSAleksa Savic 				break;
826cdbe34daSAleksa Savic 			default:
827cdbe34daSAleksa Savic 				if (channel < priv->num_fans)
828cdbe34daSAleksa Savic 					return 0444;
829cdbe34daSAleksa Savic 				break;
830cdbe34daSAleksa Savic 			}
831cdbe34daSAleksa Savic 			break;
8326ff838f2SAleksa Savic 		case hwmon_fan_pulses:
8336ff838f2SAleksa Savic 			/* Special case for Quadro flow sensor */
8346ff838f2SAleksa Savic 			if (priv->kind == quadro && channel == priv->num_fans)
8356ff838f2SAleksa Savic 				return 0644;
8366ff838f2SAleksa Savic 			break;
837b3d3be6cSAleksa Savic 		case hwmon_fan_min:
838b3d3be6cSAleksa Savic 		case hwmon_fan_max:
839b3d3be6cSAleksa Savic 		case hwmon_fan_target:
840b3d3be6cSAleksa Savic 			/* Special case for Leakshield pressure sensor */
841b3d3be6cSAleksa Savic 			if (priv->kind == leakshield && channel == 0)
842b3d3be6cSAleksa Savic 				return 0444;
843b3d3be6cSAleksa Savic 			break;
8446ff838f2SAleksa Savic 		default:
8456ff838f2SAleksa Savic 			break;
8466ff838f2SAleksa Savic 		}
8476ff838f2SAleksa Savic 		break;
8482fd3eec1SAleksa Savic 	case hwmon_power:
849aed80bb9SAleksa Savic 		switch (priv->kind) {
8507505dab7SAleksa Savic 		case aquastreamult:
8517505dab7SAleksa Savic 			/* Special case to support pump and fan power */
8527505dab7SAleksa Savic 			if (channel < 2)
8537505dab7SAleksa Savic 				return 0444;
8547505dab7SAleksa Savic 			break;
855aed80bb9SAleksa Savic 		case highflownext:
856aed80bb9SAleksa Savic 			/* Special case to support one power sensor */
857aed80bb9SAleksa Savic 			if (channel == 0)
858aed80bb9SAleksa Savic 				return 0444;
859aed80bb9SAleksa Savic 			break;
86019692f17SAleksa Savic 		case aquastreamxt:
86119692f17SAleksa Savic 			break;
862aed80bb9SAleksa Savic 		default:
863aed80bb9SAleksa Savic 			if (channel < priv->num_fans)
864aed80bb9SAleksa Savic 				return 0444;
865aed80bb9SAleksa Savic 			break;
866aed80bb9SAleksa Savic 		}
867aed80bb9SAleksa Savic 		break;
8682fd3eec1SAleksa Savic 	case hwmon_curr:
8697505dab7SAleksa Savic 		switch (priv->kind) {
8707505dab7SAleksa Savic 		case aquastreamult:
8717505dab7SAleksa Savic 			/* Special case to support pump and fan current */
8727505dab7SAleksa Savic 			if (channel < 2)
8737505dab7SAleksa Savic 				return 0444;
8747505dab7SAleksa Savic 			break;
87519692f17SAleksa Savic 		case aquastreamxt:
87619692f17SAleksa Savic 			/* Special case to support pump current */
87719692f17SAleksa Savic 			if (channel == 0)
87819692f17SAleksa Savic 				return 0444;
87919692f17SAleksa Savic 			break;
8807505dab7SAleksa Savic 		default:
881654c9735SAleksa Savic 			if (channel < priv->num_fans)
882752b9279SAleksa Savic 				return 0444;
883752b9279SAleksa Savic 			break;
8847505dab7SAleksa Savic 		}
8857505dab7SAleksa Savic 		break;
886752b9279SAleksa Savic 	case hwmon_in:
887752b9279SAleksa Savic 		switch (priv->kind) {
888752b9279SAleksa Savic 		case d5next:
889f4caa262SAleksa Savic 			/* Special case to support +5V and +12V voltage sensors */
890f4caa262SAleksa Savic 			if (channel < priv->num_fans + 2)
891752b9279SAleksa Savic 				return 0444;
892752b9279SAleksa Savic 			break;
8937505dab7SAleksa Savic 		case aquastreamult:
894aed80bb9SAleksa Savic 		case highflownext:
895aed80bb9SAleksa Savic 			/* Special case to support two voltage sensors */
896aed80bb9SAleksa Savic 			if (channel < 2)
897aed80bb9SAleksa Savic 				return 0444;
898aed80bb9SAleksa Savic 			break;
8992fd3eec1SAleksa Savic 		default:
900654c9735SAleksa Savic 			if (channel < priv->num_fans)
901654c9735SAleksa Savic 				return 0444;
9022fd3eec1SAleksa Savic 			break;
9032fd3eec1SAleksa Savic 		}
9042fd3eec1SAleksa Savic 		break;
9052fd3eec1SAleksa Savic 	default:
9062fd3eec1SAleksa Savic 		break;
9070e35f63fSAleksa Savic 	}
9080e35f63fSAleksa Savic 
9092fd3eec1SAleksa Savic 	return 0;
9102fd3eec1SAleksa Savic }
9110e35f63fSAleksa Savic 
912e0f6c370SAleksa Savic /* Read device sensors by manually requesting the sensor report (legacy way) */
aqc_legacy_read(struct aqc_data * priv)913e0f6c370SAleksa Savic static int aqc_legacy_read(struct aqc_data *priv)
914e0f6c370SAleksa Savic {
915e0f6c370SAleksa Savic 	int ret, i, sensor_value;
916e0f6c370SAleksa Savic 
917e0f6c370SAleksa Savic 	mutex_lock(&priv->mutex);
918e0f6c370SAleksa Savic 
919e0f6c370SAleksa Savic 	memset(priv->buffer, 0x00, priv->buffer_size);
920e0f6c370SAleksa Savic 	ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
921e0f6c370SAleksa Savic 				 priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
922e0f6c370SAleksa Savic 	if (ret < 0)
923e0f6c370SAleksa Savic 		goto unlock_and_return;
924e0f6c370SAleksa Savic 
925e0f6c370SAleksa Savic 	/* Temperature sensor readings */
926e0f6c370SAleksa Savic 	for (i = 0; i < priv->num_temp_sensors; i++) {
927e0f6c370SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset +
928e0f6c370SAleksa Savic 						  i * AQC_SENSOR_SIZE);
929e0f6c370SAleksa Savic 		priv->temp_input[i] = sensor_value * 10;
930e0f6c370SAleksa Savic 	}
931e0f6c370SAleksa Savic 
93219692f17SAleksa Savic 	/* Special-case sensor readings */
93319692f17SAleksa Savic 	switch (priv->kind) {
93419692f17SAleksa Savic 	case aquastreamxt:
93519692f17SAleksa Savic 		/* Info provided with every report */
93619692f17SAleksa Savic 		priv->serial_number[0] = get_unaligned_le16(priv->buffer +
93719692f17SAleksa Savic 							    priv->serial_number_start_offset);
93819692f17SAleksa Savic 		priv->firmware_version =
93919692f17SAleksa Savic 			get_unaligned_le16(priv->buffer + priv->firmware_version_offset);
94019692f17SAleksa Savic 
94119692f17SAleksa Savic 		/* Read pump speed in RPM */
94219692f17SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[0]);
94319692f17SAleksa Savic 		priv->speed_input[0] = aqc_aquastreamxt_convert_pump_rpm(sensor_value);
94419692f17SAleksa Savic 
94519692f17SAleksa Savic 		/* Read fan speed in RPM, if available */
94619692f17SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_STATUS_OFFSET);
94719692f17SAleksa Savic 		if (sensor_value == AQUASTREAMXT_FAN_STOPPED) {
94819692f17SAleksa Savic 			priv->speed_input[1] = 0;
94919692f17SAleksa Savic 		} else {
95019692f17SAleksa Savic 			sensor_value =
95119692f17SAleksa Savic 				get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[1]);
95219692f17SAleksa Savic 			priv->speed_input[1] = aqc_aquastreamxt_convert_fan_rpm(sensor_value);
95319692f17SAleksa Savic 		}
95419692f17SAleksa Savic 
95519692f17SAleksa Savic 		/* Calculation derived from linear regression */
95619692f17SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
95719692f17SAleksa Savic 		priv->current_input[0] = DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52;
95819692f17SAleksa Savic 
95919692f17SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
96019692f17SAleksa Savic 		priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
96119692f17SAleksa Savic 
96219692f17SAleksa Savic 		sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET);
96319692f17SAleksa Savic 		priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63);
96419692f17SAleksa Savic 		break;
96519692f17SAleksa Savic 	default:
96619692f17SAleksa Savic 		break;
96719692f17SAleksa Savic 	}
96819692f17SAleksa Savic 
969e0f6c370SAleksa Savic 	priv->updated = jiffies;
970e0f6c370SAleksa Savic 
971e0f6c370SAleksa Savic unlock_and_return:
972e0f6c370SAleksa Savic 	mutex_unlock(&priv->mutex);
973e0f6c370SAleksa Savic 	return ret;
974e0f6c370SAleksa Savic }
975e0f6c370SAleksa Savic 
aqc_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)9762fd3eec1SAleksa Savic static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
9772fd3eec1SAleksa Savic 		    int channel, long *val)
9782fd3eec1SAleksa Savic {
979752b9279SAleksa Savic 	int ret;
9802fd3eec1SAleksa Savic 	struct aqc_data *priv = dev_get_drvdata(dev);
9812fd3eec1SAleksa Savic 
982e0f6c370SAleksa Savic 	if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) {
983e0f6c370SAleksa Savic 		if (priv->status_report_id != 0) {
984e0f6c370SAleksa Savic 			/* Legacy devices require manual reads */
985e0f6c370SAleksa Savic 			ret = aqc_legacy_read(priv);
986e0f6c370SAleksa Savic 			if (ret < 0)
9870e35f63fSAleksa Savic 				return -ENODATA;
988e0f6c370SAleksa Savic 		} else {
989e0f6c370SAleksa Savic 			return -ENODATA;
990e0f6c370SAleksa Savic 		}
991e0f6c370SAleksa Savic 	}
9920e35f63fSAleksa Savic 
9930e35f63fSAleksa Savic 	switch (type) {
9940e35f63fSAleksa Savic 	case hwmon_temp:
995662d20b3SAleksa Savic 		switch (attr) {
996662d20b3SAleksa Savic 		case hwmon_temp_input:
9972fd3eec1SAleksa Savic 			if (priv->temp_input[channel] == -ENODATA)
9982fd3eec1SAleksa Savic 				return -ENODATA;
9992fd3eec1SAleksa Savic 
10002fd3eec1SAleksa Savic 			*val = priv->temp_input[channel];
10010e35f63fSAleksa Savic 			break;
1002662d20b3SAleksa Savic 		case hwmon_temp_offset:
1003662d20b3SAleksa Savic 			ret =
1004662d20b3SAleksa Savic 			    aqc_get_ctrl_val(priv, priv->temp_ctrl_offset +
1005d0450fc1SLeonard Anderweit 					     channel * AQC_SENSOR_SIZE, val, AQC_BE16);
1006662d20b3SAleksa Savic 			if (ret < 0)
1007662d20b3SAleksa Savic 				return ret;
1008662d20b3SAleksa Savic 
1009662d20b3SAleksa Savic 			*val *= 10;
1010662d20b3SAleksa Savic 			break;
1011662d20b3SAleksa Savic 		default:
1012662d20b3SAleksa Savic 			break;
1013662d20b3SAleksa Savic 		}
1014662d20b3SAleksa Savic 		break;
10150e35f63fSAleksa Savic 	case hwmon_fan:
10166ff838f2SAleksa Savic 		switch (attr) {
10176ff838f2SAleksa Savic 		case hwmon_fan_input:
1018b3d3be6cSAleksa Savic 			if (priv->speed_input[channel] == -ENODATA)
1019b3d3be6cSAleksa Savic 				return -ENODATA;
1020b3d3be6cSAleksa Savic 
10210e35f63fSAleksa Savic 			*val = priv->speed_input[channel];
10220e35f63fSAleksa Savic 			break;
1023b3d3be6cSAleksa Savic 		case hwmon_fan_min:
1024b3d3be6cSAleksa Savic 			*val = priv->speed_input_min[channel];
1025b3d3be6cSAleksa Savic 			break;
1026b3d3be6cSAleksa Savic 		case hwmon_fan_max:
1027b3d3be6cSAleksa Savic 			*val = priv->speed_input_max[channel];
1028b3d3be6cSAleksa Savic 			break;
1029b3d3be6cSAleksa Savic 		case hwmon_fan_target:
1030b3d3be6cSAleksa Savic 			*val = priv->speed_input_target[channel];
1031b3d3be6cSAleksa Savic 			break;
10326ff838f2SAleksa Savic 		case hwmon_fan_pulses:
1033d0450fc1SLeonard Anderweit 			ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
1034d0450fc1SLeonard Anderweit 					       val, AQC_BE16);
10356ff838f2SAleksa Savic 			if (ret < 0)
10366ff838f2SAleksa Savic 				return ret;
10376ff838f2SAleksa Savic 			break;
10386ff838f2SAleksa Savic 		default:
10396ff838f2SAleksa Savic 			break;
10406ff838f2SAleksa Savic 		}
10416ff838f2SAleksa Savic 		break;
10420e35f63fSAleksa Savic 	case hwmon_power:
10430e35f63fSAleksa Savic 		*val = priv->power_input[channel];
10440e35f63fSAleksa Savic 		break;
1045752b9279SAleksa Savic 	case hwmon_pwm:
1046bd1e92f9SLeonard Anderweit 		switch (priv->kind) {
1047bd1e92f9SLeonard Anderweit 		case aquaero:
1048bd1e92f9SLeonard Anderweit 			ret = aqc_get_ctrl_val(priv,
1049bd1e92f9SLeonard Anderweit 				AQUAERO_CTRL_PRESET_START + channel * AQUAERO_CTRL_PRESET_SIZE,
1050bd1e92f9SLeonard Anderweit 				val, AQC_BE16);
1051bd1e92f9SLeonard Anderweit 			if (ret < 0)
1052bd1e92f9SLeonard Anderweit 				return ret;
1053bd1e92f9SLeonard Anderweit 			*val = aqc_percent_to_pwm(*val);
1054bd1e92f9SLeonard Anderweit 			break;
1055bd1e92f9SLeonard Anderweit 		default:
1056d0450fc1SLeonard Anderweit 			ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
1057d0450fc1SLeonard Anderweit 					       val, AQC_BE16);
1058752b9279SAleksa Savic 			if (ret < 0)
1059752b9279SAleksa Savic 				return ret;
1060752b9279SAleksa Savic 
1061a746b368SAleksa Savic 			*val = aqc_percent_to_pwm(*val);
1062bd1e92f9SLeonard Anderweit 			break;
1063752b9279SAleksa Savic 		}
1064752b9279SAleksa Savic 		break;
10650e35f63fSAleksa Savic 	case hwmon_in:
10660e35f63fSAleksa Savic 		*val = priv->voltage_input[channel];
10670e35f63fSAleksa Savic 		break;
10680e35f63fSAleksa Savic 	case hwmon_curr:
10690e35f63fSAleksa Savic 		*val = priv->current_input[channel];
10700e35f63fSAleksa Savic 		break;
10710e35f63fSAleksa Savic 	default:
10720e35f63fSAleksa Savic 		return -EOPNOTSUPP;
10730e35f63fSAleksa Savic 	}
10740e35f63fSAleksa Savic 
10750e35f63fSAleksa Savic 	return 0;
10760e35f63fSAleksa Savic }
10770e35f63fSAleksa Savic 
aqc_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)10782fd3eec1SAleksa Savic static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
10790e35f63fSAleksa Savic 			   int channel, const char **str)
10800e35f63fSAleksa Savic {
10812fd3eec1SAleksa Savic 	struct aqc_data *priv = dev_get_drvdata(dev);
10822fd3eec1SAleksa Savic 
10833d2e9f58SAleksa Savic 	/* Number of sensors that are not calculated */
10843d2e9f58SAleksa Savic 	int num_non_calc_sensors = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
10853d2e9f58SAleksa Savic 
10860e35f63fSAleksa Savic 	switch (type) {
10870e35f63fSAleksa Savic 	case hwmon_temp:
10883d2e9f58SAleksa Savic 		if (channel < priv->num_temp_sensors) {
1089752b9279SAleksa Savic 			*str = priv->temp_label[channel];
10903d2e9f58SAleksa Savic 		} else {
10913d2e9f58SAleksa Savic 			if (priv->kind == aquaero && channel >= num_non_calc_sensors)
10923d2e9f58SAleksa Savic 				*str =
10933d2e9f58SAleksa Savic 				    priv->calc_virt_temp_label[channel - num_non_calc_sensors];
1094e2769f5eSAleksa Savic 			else
1095e2769f5eSAleksa Savic 				*str = priv->virtual_temp_label[channel - priv->num_temp_sensors];
10963d2e9f58SAleksa Savic 		}
10970e35f63fSAleksa Savic 		break;
10980e35f63fSAleksa Savic 	case hwmon_fan:
1099752b9279SAleksa Savic 		*str = priv->speed_label[channel];
11000e35f63fSAleksa Savic 		break;
11010e35f63fSAleksa Savic 	case hwmon_power:
1102752b9279SAleksa Savic 		*str = priv->power_label[channel];
11030e35f63fSAleksa Savic 		break;
11040e35f63fSAleksa Savic 	case hwmon_in:
1105752b9279SAleksa Savic 		*str = priv->voltage_label[channel];
1106752b9279SAleksa Savic 		break;
1107752b9279SAleksa Savic 	case hwmon_curr:
1108752b9279SAleksa Savic 		*str = priv->current_label[channel];
1109752b9279SAleksa Savic 		break;
1110752b9279SAleksa Savic 	default:
1111752b9279SAleksa Savic 		return -EOPNOTSUPP;
1112752b9279SAleksa Savic 	}
1113752b9279SAleksa Savic 
1114752b9279SAleksa Savic 	return 0;
1115752b9279SAleksa Savic }
1116752b9279SAleksa Savic 
aqc_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)1117752b9279SAleksa Savic static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
1118752b9279SAleksa Savic 		     long val)
1119752b9279SAleksa Savic {
1120752b9279SAleksa Savic 	int ret, pwm_value;
1121bd1e92f9SLeonard Anderweit 	/* Arrays for setting multiple values at once in the control report */
1122bd1e92f9SLeonard Anderweit 	int ctrl_values_offsets[4];
1123bd1e92f9SLeonard Anderweit 	long ctrl_values[4];
1124bd1e92f9SLeonard Anderweit 	int ctrl_values_types[4];
1125752b9279SAleksa Savic 	struct aqc_data *priv = dev_get_drvdata(dev);
1126752b9279SAleksa Savic 
1127752b9279SAleksa Savic 	switch (type) {
1128662d20b3SAleksa Savic 	case hwmon_temp:
1129662d20b3SAleksa Savic 		switch (attr) {
1130662d20b3SAleksa Savic 		case hwmon_temp_offset:
1131662d20b3SAleksa Savic 			/* Limit temp offset to +/- 15K as in the official software */
1132662d20b3SAleksa Savic 			val = clamp_val(val, -15000, 15000) / 10;
1133662d20b3SAleksa Savic 			ret =
1134662d20b3SAleksa Savic 			    aqc_set_ctrl_val(priv, priv->temp_ctrl_offset +
1135d0450fc1SLeonard Anderweit 					     channel * AQC_SENSOR_SIZE, val, AQC_BE16);
1136662d20b3SAleksa Savic 			if (ret < 0)
1137662d20b3SAleksa Savic 				return ret;
1138662d20b3SAleksa Savic 			break;
1139662d20b3SAleksa Savic 		default:
1140662d20b3SAleksa Savic 			return -EOPNOTSUPP;
1141662d20b3SAleksa Savic 		}
1142662d20b3SAleksa Savic 		break;
11436ff838f2SAleksa Savic 	case hwmon_fan:
11446ff838f2SAleksa Savic 		switch (attr) {
11456ff838f2SAleksa Savic 		case hwmon_fan_pulses:
11466ff838f2SAleksa Savic 			val = clamp_val(val, 10, 1000);
1147d0450fc1SLeonard Anderweit 			ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
1148d0450fc1SLeonard Anderweit 					       val, AQC_BE16);
11496ff838f2SAleksa Savic 			if (ret < 0)
11506ff838f2SAleksa Savic 				return ret;
11516ff838f2SAleksa Savic 			break;
11526ff838f2SAleksa Savic 		default:
11536ff838f2SAleksa Savic 			break;
11546ff838f2SAleksa Savic 		}
11556ff838f2SAleksa Savic 		break;
1156752b9279SAleksa Savic 	case hwmon_pwm:
1157752b9279SAleksa Savic 		switch (attr) {
1158752b9279SAleksa Savic 		case hwmon_pwm_input:
1159752b9279SAleksa Savic 			pwm_value = aqc_pwm_to_percent(val);
1160752b9279SAleksa Savic 			if (pwm_value < 0)
1161752b9279SAleksa Savic 				return pwm_value;
1162752b9279SAleksa Savic 
1163bd1e92f9SLeonard Anderweit 			switch (priv->kind) {
1164bd1e92f9SLeonard Anderweit 			case aquaero:
1165bd1e92f9SLeonard Anderweit 				/* Write pwm value to preset corresponding to the channel */
1166bd1e92f9SLeonard Anderweit 				ctrl_values_offsets[0] = AQUAERO_CTRL_PRESET_START +
1167bd1e92f9SLeonard Anderweit 				    channel * AQUAERO_CTRL_PRESET_SIZE;
1168bd1e92f9SLeonard Anderweit 				ctrl_values[0] = pwm_value;
1169bd1e92f9SLeonard Anderweit 				ctrl_values_types[0] = AQC_BE16;
1170bd1e92f9SLeonard Anderweit 
1171bd1e92f9SLeonard Anderweit 				/* Write preset number in fan control source */
1172bd1e92f9SLeonard Anderweit 				ctrl_values_offsets[1] = priv->fan_ctrl_offsets[channel] +
1173bd1e92f9SLeonard Anderweit 				    AQUAERO_FAN_CTRL_SRC_OFFSET;
1174bd1e92f9SLeonard Anderweit 				ctrl_values[1] = AQUAERO_CTRL_PRESET_ID + channel;
1175bd1e92f9SLeonard Anderweit 				ctrl_values_types[1] = AQC_BE16;
1176bd1e92f9SLeonard Anderweit 
1177bd1e92f9SLeonard Anderweit 				/* Set minimum power to 0 to allow the fan to turn off */
1178bd1e92f9SLeonard Anderweit 				ctrl_values_offsets[2] = priv->fan_ctrl_offsets[channel] +
1179bd1e92f9SLeonard Anderweit 				    AQUAERO_FAN_CTRL_MIN_PWR_OFFSET;
1180bd1e92f9SLeonard Anderweit 				ctrl_values[2] = 0;
1181bd1e92f9SLeonard Anderweit 				ctrl_values_types[2] = AQC_BE16;
1182bd1e92f9SLeonard Anderweit 
1183bd1e92f9SLeonard Anderweit 				/* Set maximum power to 255 to allow the fan to reach max speed */
1184bd1e92f9SLeonard Anderweit 				ctrl_values_offsets[3] = priv->fan_ctrl_offsets[channel] +
1185bd1e92f9SLeonard Anderweit 				    AQUAERO_FAN_CTRL_MAX_PWR_OFFSET;
1186bd1e92f9SLeonard Anderweit 				ctrl_values[3] = aqc_pwm_to_percent(255);
1187bd1e92f9SLeonard Anderweit 				ctrl_values_types[3] = AQC_BE16;
1188bd1e92f9SLeonard Anderweit 
1189bd1e92f9SLeonard Anderweit 				ret = aqc_set_ctrl_vals(priv, ctrl_values_offsets, ctrl_values,
1190bd1e92f9SLeonard Anderweit 							ctrl_values_types, 4);
1191bd1e92f9SLeonard Anderweit 				if (ret < 0)
1192bd1e92f9SLeonard Anderweit 					return ret;
1193bd1e92f9SLeonard Anderweit 				break;
1194bd1e92f9SLeonard Anderweit 			default:
1195654c9735SAleksa Savic 				ret = aqc_set_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
1196d0450fc1SLeonard Anderweit 						       pwm_value, AQC_BE16);
1197752b9279SAleksa Savic 				if (ret < 0)
1198752b9279SAleksa Savic 					return ret;
1199bd1e92f9SLeonard Anderweit 				break;
12002fd3eec1SAleksa Savic 			}
12010e35f63fSAleksa Savic 			break;
12022fd3eec1SAleksa Savic 		default:
12032fd3eec1SAleksa Savic 			break;
12042fd3eec1SAleksa Savic 		}
12050e35f63fSAleksa Savic 		break;
12060e35f63fSAleksa Savic 	default:
12070e35f63fSAleksa Savic 		return -EOPNOTSUPP;
12080e35f63fSAleksa Savic 	}
12090e35f63fSAleksa Savic 
12100e35f63fSAleksa Savic 	return 0;
12110e35f63fSAleksa Savic }
12120e35f63fSAleksa Savic 
12132fd3eec1SAleksa Savic static const struct hwmon_ops aqc_hwmon_ops = {
12142fd3eec1SAleksa Savic 	.is_visible = aqc_is_visible,
12152fd3eec1SAleksa Savic 	.read = aqc_read,
12162fd3eec1SAleksa Savic 	.read_string = aqc_read_string,
1217752b9279SAleksa Savic 	.write = aqc_write
12180e35f63fSAleksa Savic };
12190e35f63fSAleksa Savic 
1220832dc510SKrzysztof Kozlowski static const struct hwmon_channel_info * const aqc_info[] = {
12212fd3eec1SAleksa Savic 	HWMON_CHANNEL_INFO(temp,
1222662d20b3SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1223662d20b3SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1224662d20b3SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1225662d20b3SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1226866e630aSLeonard Anderweit 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1227866e630aSLeonard Anderweit 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1228866e630aSLeonard Anderweit 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1229866e630aSLeonard Anderweit 			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
1230e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1231e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1232e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1233e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1234e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1235e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1236e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1237e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1238e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1239e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
1240e2769f5eSAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL,
12412fd3eec1SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL),
12422fd3eec1SAleksa Savic 	HWMON_CHANNEL_INFO(fan,
1243b3d3be6cSAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
1244b3d3be6cSAleksa Savic 			   HWMON_F_TARGET,
1245752b9279SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
1246752b9279SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
1247752b9279SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
12486ff838f2SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_PULSES,
1249752b9279SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
1250752b9279SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
12512fd3eec1SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL),
12522fd3eec1SAleksa Savic 	HWMON_CHANNEL_INFO(power,
12532fd3eec1SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1254752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1255752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1256752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1257752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1258752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
1259752b9279SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL,
12602fd3eec1SAleksa Savic 			   HWMON_P_INPUT | HWMON_P_LABEL),
1261752b9279SAleksa Savic 	HWMON_CHANNEL_INFO(pwm,
1262752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1263752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1264752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1265752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1266752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1267752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1268752b9279SAleksa Savic 			   HWMON_PWM_INPUT,
1269752b9279SAleksa Savic 			   HWMON_PWM_INPUT),
12702fd3eec1SAleksa Savic 	HWMON_CHANNEL_INFO(in,
12712fd3eec1SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
12722fd3eec1SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
1273752b9279SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
1274752b9279SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
1275752b9279SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
1276752b9279SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
1277752b9279SAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL,
12780e35f63fSAleksa Savic 			   HWMON_I_INPUT | HWMON_I_LABEL),
12792fd3eec1SAleksa Savic 	HWMON_CHANNEL_INFO(curr,
12802fd3eec1SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1281752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1282752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1283752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1284752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1285752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
1286752b9279SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL,
12872fd3eec1SAleksa Savic 			   HWMON_C_INPUT | HWMON_C_LABEL),
12880e35f63fSAleksa Savic 	NULL
12890e35f63fSAleksa Savic };
12900e35f63fSAleksa Savic 
12912fd3eec1SAleksa Savic static const struct hwmon_chip_info aqc_chip_info = {
12922fd3eec1SAleksa Savic 	.ops = &aqc_hwmon_ops,
12932fd3eec1SAleksa Savic 	.info = aqc_info,
12940e35f63fSAleksa Savic };
12950e35f63fSAleksa Savic 
aqc_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)1296229b159cSJack Doan static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)
12970e35f63fSAleksa Savic {
1298e2769f5eSAleksa Savic 	int i, j, sensor_value;
12992fd3eec1SAleksa Savic 	struct aqc_data *priv;
13000e35f63fSAleksa Savic 
13012fd3eec1SAleksa Savic 	if (report->id != STATUS_REPORT_ID)
13020e35f63fSAleksa Savic 		return 0;
13030e35f63fSAleksa Savic 
13040e35f63fSAleksa Savic 	priv = hid_get_drvdata(hdev);
13050e35f63fSAleksa Savic 
13060e35f63fSAleksa Savic 	/* Info provided with every report */
1307ad2f0811SLeonard Anderweit 	priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
1308ad2f0811SLeonard Anderweit 	priv->serial_number[1] = get_unaligned_be16(data + priv->serial_number_start_offset +
1309ad2f0811SLeonard Anderweit 						    SERIAL_PART_OFFSET);
1310ad2f0811SLeonard Anderweit 	priv->firmware_version = get_unaligned_be16(data + priv->firmware_version_offset);
13110e35f63fSAleksa Savic 
1312e2769f5eSAleksa Savic 	/* Physical temperature sensor readings */
1313654c9735SAleksa Savic 	for (i = 0; i < priv->num_temp_sensors; i++) {
1314654c9735SAleksa Savic 		sensor_value = get_unaligned_be16(data +
1315654c9735SAleksa Savic 						  priv->temp_sensor_start_offset +
13168bcb02bdSLeonard Anderweit 						  i * AQC_SENSOR_SIZE);
1317fdbfd330SAleksa Savic 		if (sensor_value == AQC_SENSOR_NA)
1318229b159cSJack Doan 			priv->temp_input[i] = -ENODATA;
1319229b159cSJack Doan 		else
1320229b159cSJack Doan 			priv->temp_input[i] = sensor_value * 10;
1321229b159cSJack Doan 	}
1322752b9279SAleksa Savic 
1323e2769f5eSAleksa Savic 	/* Virtual temperature sensor readings */
1324e2769f5eSAleksa Savic 	for (j = 0; j < priv->num_virtual_temp_sensors; j++) {
1325e2769f5eSAleksa Savic 		sensor_value = get_unaligned_be16(data +
1326e2769f5eSAleksa Savic 						  priv->virtual_temp_sensor_start_offset +
13278bcb02bdSLeonard Anderweit 						  j * AQC_SENSOR_SIZE);
1328fdbfd330SAleksa Savic 		if (sensor_value == AQC_SENSOR_NA)
1329e2769f5eSAleksa Savic 			priv->temp_input[i] = -ENODATA;
1330e2769f5eSAleksa Savic 		else
1331e2769f5eSAleksa Savic 			priv->temp_input[i] = sensor_value * 10;
1332e2769f5eSAleksa Savic 		i++;
1333e2769f5eSAleksa Savic 	}
1334e2769f5eSAleksa Savic 
1335752b9279SAleksa Savic 	/* Fan speed and related readings */
1336654c9735SAleksa Savic 	for (i = 0; i < priv->num_fans; i++) {
1337752b9279SAleksa Savic 		priv->speed_input[i] =
1338249c7521SLeonard Anderweit 		    get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
1339249c7521SLeonard Anderweit 				       priv->fan_structure->speed);
1340752b9279SAleksa Savic 		priv->power_input[i] =
1341654c9735SAleksa Savic 		    get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
1342249c7521SLeonard Anderweit 				       priv->fan_structure->power) * 10000;
1343752b9279SAleksa Savic 		priv->voltage_input[i] =
1344654c9735SAleksa Savic 		    get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
1345249c7521SLeonard Anderweit 				       priv->fan_structure->voltage) * 10;
1346752b9279SAleksa Savic 		priv->current_input[i] =
1347249c7521SLeonard Anderweit 		    get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
1348249c7521SLeonard Anderweit 				       priv->fan_structure->curr);
1349752b9279SAleksa Savic 	}
1350752b9279SAleksa Savic 
1351a2ba7ee2SLeonard Anderweit 	/* Flow sensor readings */
1352a2ba7ee2SLeonard Anderweit 	for (j = 0; j < priv->num_flow_sensors; j++) {
1353a2ba7ee2SLeonard Anderweit 		priv->speed_input[i] = get_unaligned_be16(data + priv->flow_sensors_start_offset +
1354a2ba7ee2SLeonard Anderweit 							  j * AQC_SENSOR_SIZE);
1355a2ba7ee2SLeonard Anderweit 		i++;
1356a2ba7ee2SLeonard Anderweit 	}
1357a2ba7ee2SLeonard Anderweit 
1358654c9735SAleksa Savic 	if (priv->power_cycle_count_offset != 0)
1359654c9735SAleksa Savic 		priv->power_cycles = get_unaligned_be32(data + priv->power_cycle_count_offset);
1360654c9735SAleksa Savic 
1361654c9735SAleksa Savic 	/* Special-case sensor readings */
1362654c9735SAleksa Savic 	switch (priv->kind) {
13633d2e9f58SAleksa Savic 	case aquaero:
13643d2e9f58SAleksa Savic 		/* Read calculated virtual temp sensors */
13653d2e9f58SAleksa Savic 		i = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
13663d2e9f58SAleksa Savic 		for (j = 0; j < priv->num_calc_virt_temp_sensors; j++) {
13673d2e9f58SAleksa Savic 			sensor_value = get_unaligned_be16(data +
13683d2e9f58SAleksa Savic 					priv->calc_virt_temp_sensor_start_offset +
13693d2e9f58SAleksa Savic 					j * AQC_SENSOR_SIZE);
1370fdbfd330SAleksa Savic 			if (sensor_value == AQC_SENSOR_NA)
13713d2e9f58SAleksa Savic 				priv->temp_input[i] = -ENODATA;
13723d2e9f58SAleksa Savic 			else
13733d2e9f58SAleksa Savic 				priv->temp_input[i] = sensor_value * 10;
13743d2e9f58SAleksa Savic 			i++;
13753d2e9f58SAleksa Savic 		}
13763d2e9f58SAleksa Savic 		break;
13777505dab7SAleksa Savic 	case aquastreamult:
13787505dab7SAleksa Savic 		priv->speed_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_OFFSET);
13797505dab7SAleksa Savic 		priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
13807505dab7SAleksa Savic 		priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
13817505dab7SAleksa Savic 
13827505dab7SAleksa Savic 		priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
13837505dab7SAleksa Savic 
13847505dab7SAleksa Savic 		priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
13857505dab7SAleksa Savic 
13867505dab7SAleksa Savic 		priv->current_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_CURRENT);
13877505dab7SAleksa Savic 		break;
1388654c9735SAleksa Savic 	case d5next:
1389654c9735SAleksa Savic 		priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
1390f4caa262SAleksa Savic 		priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10;
1391752b9279SAleksa Savic 		break;
1392aed80bb9SAleksa Savic 	case highflownext:
1393aed80bb9SAleksa Savic 		/* If external temp sensor is not connected, its power reading is also N/A */
1394aed80bb9SAleksa Savic 		if (priv->temp_input[1] == -ENODATA)
1395aed80bb9SAleksa Savic 			priv->power_input[0] = -ENODATA;
1396aed80bb9SAleksa Savic 		else
1397aed80bb9SAleksa Savic 			priv->power_input[0] =
1398aed80bb9SAleksa Savic 			    get_unaligned_be16(data + HIGHFLOWNEXT_POWER) * 1000000;
1399aed80bb9SAleksa Savic 
1400aed80bb9SAleksa Savic 		priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10;
1401aed80bb9SAleksa Savic 		priv->voltage_input[1] =
1402aed80bb9SAleksa Savic 		    get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10;
1403aed80bb9SAleksa Savic 
1404aed80bb9SAleksa Savic 		priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
1405aed80bb9SAleksa Savic 		priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
1406aed80bb9SAleksa Savic 		break;
1407b3d3be6cSAleksa Savic 	case leakshield:
1408b3d3be6cSAleksa Savic 		priv->speed_input[0] =
1409b3d3be6cSAleksa Savic 		    ((s16)get_unaligned_be16(data + LEAKSHIELD_PRESSURE_ADJUSTED)) * 100;
1410b3d3be6cSAleksa Savic 		priv->speed_input_min[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MIN) * 100;
1411b3d3be6cSAleksa Savic 		priv->speed_input_target[0] =
1412b3d3be6cSAleksa Savic 		    get_unaligned_be16(data + LEAKSHIELD_PRESSURE_TARGET) * 100;
1413b3d3be6cSAleksa Savic 		priv->speed_input_max[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MAX) * 100;
1414b3d3be6cSAleksa Savic 
1415b3d3be6cSAleksa Savic 		priv->speed_input[1] = get_unaligned_be16(data + LEAKSHIELD_PUMP_RPM_IN);
1416b3d3be6cSAleksa Savic 		if (priv->speed_input[1] == AQC_SENSOR_NA)
1417b3d3be6cSAleksa Savic 			priv->speed_input[1] = -ENODATA;
1418b3d3be6cSAleksa Savic 
1419b3d3be6cSAleksa Savic 		priv->speed_input[2] = get_unaligned_be16(data + LEAKSHIELD_FLOW_IN);
1420b3d3be6cSAleksa Savic 		if (priv->speed_input[2] == AQC_SENSOR_NA)
1421b3d3be6cSAleksa Savic 			priv->speed_input[2] = -ENODATA;
1422b3d3be6cSAleksa Savic 
1423b3d3be6cSAleksa Savic 		priv->speed_input[3] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_VOLUME);
1424b3d3be6cSAleksa Savic 		priv->speed_input[4] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_FILLED);
1425b3d3be6cSAleksa Savic 
1426b3d3be6cSAleksa Savic 		/* Second temp sensor is not positioned after the first one, read it here */
1427b3d3be6cSAleksa Savic 		priv->temp_input[1] = get_unaligned_be16(data + LEAKSHIELD_TEMPERATURE_2) * 10;
1428b3d3be6cSAleksa Savic 		break;
14292fd3eec1SAleksa Savic 	default:
14302fd3eec1SAleksa Savic 		break;
14312fd3eec1SAleksa Savic 	}
14320e35f63fSAleksa Savic 
14330e35f63fSAleksa Savic 	priv->updated = jiffies;
14340e35f63fSAleksa Savic 
14350e35f63fSAleksa Savic 	return 0;
14360e35f63fSAleksa Savic }
14370e35f63fSAleksa Savic 
14380e35f63fSAleksa Savic #ifdef CONFIG_DEBUG_FS
14390e35f63fSAleksa Savic 
serial_number_show(struct seq_file * seqf,void * unused)14400e35f63fSAleksa Savic static int serial_number_show(struct seq_file *seqf, void *unused)
14410e35f63fSAleksa Savic {
14422fd3eec1SAleksa Savic 	struct aqc_data *priv = seqf->private;
14430e35f63fSAleksa Savic 
14440e35f63fSAleksa Savic 	seq_printf(seqf, "%05u-%05u\n", priv->serial_number[0], priv->serial_number[1]);
14450e35f63fSAleksa Savic 
14460e35f63fSAleksa Savic 	return 0;
14470e35f63fSAleksa Savic }
14480e35f63fSAleksa Savic DEFINE_SHOW_ATTRIBUTE(serial_number);
14490e35f63fSAleksa Savic 
firmware_version_show(struct seq_file * seqf,void * unused)14500e35f63fSAleksa Savic static int firmware_version_show(struct seq_file *seqf, void *unused)
14510e35f63fSAleksa Savic {
14522fd3eec1SAleksa Savic 	struct aqc_data *priv = seqf->private;
14530e35f63fSAleksa Savic 
14540e35f63fSAleksa Savic 	seq_printf(seqf, "%u\n", priv->firmware_version);
14550e35f63fSAleksa Savic 
14560e35f63fSAleksa Savic 	return 0;
14570e35f63fSAleksa Savic }
14580e35f63fSAleksa Savic DEFINE_SHOW_ATTRIBUTE(firmware_version);
14590e35f63fSAleksa Savic 
power_cycles_show(struct seq_file * seqf,void * unused)14600e35f63fSAleksa Savic static int power_cycles_show(struct seq_file *seqf, void *unused)
14610e35f63fSAleksa Savic {
14622fd3eec1SAleksa Savic 	struct aqc_data *priv = seqf->private;
14630e35f63fSAleksa Savic 
14640e35f63fSAleksa Savic 	seq_printf(seqf, "%u\n", priv->power_cycles);
14650e35f63fSAleksa Savic 
14660e35f63fSAleksa Savic 	return 0;
14670e35f63fSAleksa Savic }
14680e35f63fSAleksa Savic DEFINE_SHOW_ATTRIBUTE(power_cycles);
14690e35f63fSAleksa Savic 
aqc_debugfs_init(struct aqc_data * priv)14702fd3eec1SAleksa Savic static void aqc_debugfs_init(struct aqc_data *priv)
14710e35f63fSAleksa Savic {
14722fd3eec1SAleksa Savic 	char name[64];
14730e35f63fSAleksa Savic 
14742fd3eec1SAleksa Savic 	scnprintf(name, sizeof(name), "%s_%s-%s", "aquacomputer", priv->name,
14752fd3eec1SAleksa Savic 		  dev_name(&priv->hdev->dev));
14760e35f63fSAleksa Savic 
14770e35f63fSAleksa Savic 	priv->debugfs = debugfs_create_dir(name, NULL);
14782fd3eec1SAleksa Savic 
1479e0f6c370SAleksa Savic 	if (priv->serial_number_start_offset != 0)
1480e0f6c370SAleksa Savic 		debugfs_create_file("serial_number", 0444, priv->debugfs, priv,
1481e0f6c370SAleksa Savic 				    &serial_number_fops);
1482e0f6c370SAleksa Savic 	if (priv->firmware_version_offset != 0)
1483e0f6c370SAleksa Savic 		debugfs_create_file("firmware_version", 0444, priv->debugfs, priv,
1484e0f6c370SAleksa Savic 				    &firmware_version_fops);
1485654c9735SAleksa Savic 	if (priv->power_cycle_count_offset != 0)
14860e35f63fSAleksa Savic 		debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
14870e35f63fSAleksa Savic }
14880e35f63fSAleksa Savic 
14890e35f63fSAleksa Savic #else
14900e35f63fSAleksa Savic 
aqc_debugfs_init(struct aqc_data * priv)14912fd3eec1SAleksa Savic static void aqc_debugfs_init(struct aqc_data *priv)
14920e35f63fSAleksa Savic {
14930e35f63fSAleksa Savic }
14940e35f63fSAleksa Savic 
14950e35f63fSAleksa Savic #endif
14960e35f63fSAleksa Savic 
aqc_probe(struct hid_device * hdev,const struct hid_device_id * id)14972fd3eec1SAleksa Savic static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
14980e35f63fSAleksa Savic {
14992fd3eec1SAleksa Savic 	struct aqc_data *priv;
15000e35f63fSAleksa Savic 	int ret;
15010e35f63fSAleksa Savic 
15020e35f63fSAleksa Savic 	priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
15030e35f63fSAleksa Savic 	if (!priv)
15040e35f63fSAleksa Savic 		return -ENOMEM;
15050e35f63fSAleksa Savic 
15060e35f63fSAleksa Savic 	priv->hdev = hdev;
15070e35f63fSAleksa Savic 	hid_set_drvdata(hdev, priv);
15080e35f63fSAleksa Savic 
15092fd3eec1SAleksa Savic 	priv->updated = jiffies - STATUS_UPDATE_INTERVAL;
15100e35f63fSAleksa Savic 
15110e35f63fSAleksa Savic 	ret = hid_parse(hdev);
15120e35f63fSAleksa Savic 	if (ret)
15130e35f63fSAleksa Savic 		return ret;
15140e35f63fSAleksa Savic 
15150e35f63fSAleksa Savic 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
15160e35f63fSAleksa Savic 	if (ret)
15170e35f63fSAleksa Savic 		return ret;
15180e35f63fSAleksa Savic 
15190e35f63fSAleksa Savic 	ret = hid_hw_open(hdev);
15200e35f63fSAleksa Savic 	if (ret)
15210e35f63fSAleksa Savic 		goto fail_and_stop;
15220e35f63fSAleksa Savic 
15232fd3eec1SAleksa Savic 	switch (hdev->product) {
15242c552111SLeonard Anderweit 	case USB_PRODUCT_ID_AQUAERO:
15252c552111SLeonard Anderweit 		/*
15262c552111SLeonard Anderweit 		 * Aquaero presents itself as three HID devices under the same product ID:
15272c552111SLeonard Anderweit 		 * "aquaero keyboard/mouse", "aquaero System Control" and "aquaero Device",
15282c552111SLeonard Anderweit 		 * which is the one we want to communicate with. Unlike most other Aquacomputer
15292c552111SLeonard Anderweit 		 * devices, Aquaero does not return meaningful data when explicitly requested
15302c552111SLeonard Anderweit 		 * using GET_FEATURE_REPORT.
15312c552111SLeonard Anderweit 		 *
15322c552111SLeonard Anderweit 		 * The difference between "aquaero Device" and the other two is in the collections
15332c552111SLeonard Anderweit 		 * they present. The two other devices have the type of the second element in
15342c552111SLeonard Anderweit 		 * their respective collections set to 1, while the real device has it set to 0.
15352c552111SLeonard Anderweit 		 */
15362c552111SLeonard Anderweit 		if (hdev->collection[1].type != 0) {
15372c552111SLeonard Anderweit 			ret = -ENODEV;
15382c552111SLeonard Anderweit 			goto fail_and_close;
15392c552111SLeonard Anderweit 		}
15402c552111SLeonard Anderweit 
15412c552111SLeonard Anderweit 		priv->kind = aquaero;
15422c552111SLeonard Anderweit 
15432c552111SLeonard Anderweit 		priv->num_fans = AQUAERO_NUM_FANS;
15442c552111SLeonard Anderweit 		priv->fan_sensor_offsets = aquaero_sensor_fan_offsets;
1545bd1e92f9SLeonard Anderweit 		priv->fan_ctrl_offsets = aquaero_ctrl_fan_offsets;
15462c552111SLeonard Anderweit 
15472c552111SLeonard Anderweit 		priv->num_temp_sensors = AQUAERO_NUM_SENSORS;
15482c552111SLeonard Anderweit 		priv->temp_sensor_start_offset = AQUAERO_SENSOR_START;
15492c552111SLeonard Anderweit 		priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS;
15502c552111SLeonard Anderweit 		priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START;
15513d2e9f58SAleksa Savic 		priv->num_calc_virt_temp_sensors = AQUAERO_NUM_CALC_VIRTUAL_SENSORS;
15523d2e9f58SAleksa Savic 		priv->calc_virt_temp_sensor_start_offset = AQUAERO_CALC_VIRTUAL_SENSOR_START;
15532c552111SLeonard Anderweit 		priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS;
15542c552111SLeonard Anderweit 		priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START;
15552c552111SLeonard Anderweit 
15566c83ccb1SLeonard Anderweit 		priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE;
1557866e630aSLeonard Anderweit 		priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET;
1558*56b930dcSAleksa Savic 		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
15596c83ccb1SLeonard Anderweit 
15602c552111SLeonard Anderweit 		priv->temp_label = label_temp_sensors;
15612c552111SLeonard Anderweit 		priv->virtual_temp_label = label_virtual_temp_sensors;
15623d2e9f58SAleksa Savic 		priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors;
15632c552111SLeonard Anderweit 		priv->speed_label = label_aquaero_speeds;
15642c552111SLeonard Anderweit 		priv->power_label = label_fan_power;
15652c552111SLeonard Anderweit 		priv->voltage_label = label_fan_voltage;
15662c552111SLeonard Anderweit 		priv->current_label = label_fan_current;
15672c552111SLeonard Anderweit 		break;
15682fd3eec1SAleksa Savic 	case USB_PRODUCT_ID_D5NEXT:
15692fd3eec1SAleksa Savic 		priv->kind = d5next;
1570752b9279SAleksa Savic 
1571654c9735SAleksa Savic 		priv->num_fans = D5NEXT_NUM_FANS;
1572654c9735SAleksa Savic 		priv->fan_sensor_offsets = d5next_sensor_fan_offsets;
157309e89309SAleksa Savic 		priv->fan_ctrl_offsets = d5next_ctrl_fan_offsets;
1574d5d896b8SAleksa Savic 
1575654c9735SAleksa Savic 		priv->num_temp_sensors = D5NEXT_NUM_SENSORS;
1576654c9735SAleksa Savic 		priv->temp_sensor_start_offset = D5NEXT_COOLANT_TEMP;
1577e2769f5eSAleksa Savic 		priv->num_virtual_temp_sensors = D5NEXT_NUM_VIRTUAL_SENSORS;
1578e2769f5eSAleksa Savic 		priv->virtual_temp_sensor_start_offset = D5NEXT_VIRTUAL_SENSORS_START;
1579662d20b3SAleksa Savic 		priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET;
1580654c9735SAleksa Savic 
1581d5d896b8SAleksa Savic 		priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE;
1582*56b930dcSAleksa Savic 		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
1583d5d896b8SAleksa Savic 
1584d5d896b8SAleksa Savic 		priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES;
1585d5d896b8SAleksa Savic 
1586752b9279SAleksa Savic 		priv->temp_label = label_d5next_temp;
1587e2769f5eSAleksa Savic 		priv->virtual_temp_label = label_virtual_temp_sensors;
1588752b9279SAleksa Savic 		priv->speed_label = label_d5next_speeds;
1589752b9279SAleksa Savic 		priv->power_label = label_d5next_power;
1590752b9279SAleksa Savic 		priv->voltage_label = label_d5next_voltages;
1591752b9279SAleksa Savic 		priv->current_label = label_d5next_current;
15922fd3eec1SAleksa Savic 		break;
1593229b159cSJack Doan 	case USB_PRODUCT_ID_FARBWERK:
1594229b159cSJack Doan 		priv->kind = farbwerk;
1595229b159cSJack Doan 
1596654c9735SAleksa Savic 		priv->num_fans = 0;
1597d5d896b8SAleksa Savic 
1598654c9735SAleksa Savic 		priv->num_temp_sensors = FARBWERK_NUM_SENSORS;
1599654c9735SAleksa Savic 		priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
1600d5d896b8SAleksa Savic 
1601229b159cSJack Doan 		priv->temp_label = label_temp_sensors;
1602229b159cSJack Doan 		break;
16032fd3eec1SAleksa Savic 	case USB_PRODUCT_ID_FARBWERK360:
16042fd3eec1SAleksa Savic 		priv->kind = farbwerk360;
1605752b9279SAleksa Savic 
1606654c9735SAleksa Savic 		priv->num_fans = 0;
1607d5d896b8SAleksa Savic 
1608654c9735SAleksa Savic 		priv->num_temp_sensors = FARBWERK360_NUM_SENSORS;
1609654c9735SAleksa Savic 		priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START;
1610e2769f5eSAleksa Savic 		priv->num_virtual_temp_sensors = FARBWERK360_NUM_VIRTUAL_SENSORS;
1611e2769f5eSAleksa Savic 		priv->virtual_temp_sensor_start_offset = FARBWERK360_VIRTUAL_SENSORS_START;
1612662d20b3SAleksa Savic 		priv->temp_ctrl_offset = FARBWERK360_TEMP_CTRL_OFFSET;
1613d5d896b8SAleksa Savic 
1614d5d896b8SAleksa Savic 		priv->buffer_size = FARBWERK360_CTRL_REPORT_SIZE;
1615d5d896b8SAleksa Savic 
1616752b9279SAleksa Savic 		priv->temp_label = label_temp_sensors;
1617e2769f5eSAleksa Savic 		priv->virtual_temp_label = label_virtual_temp_sensors;
1618752b9279SAleksa Savic 		break;
1619752b9279SAleksa Savic 	case USB_PRODUCT_ID_OCTO:
1620752b9279SAleksa Savic 		priv->kind = octo;
1621654c9735SAleksa Savic 
1622654c9735SAleksa Savic 		priv->num_fans = OCTO_NUM_FANS;
1623654c9735SAleksa Savic 		priv->fan_sensor_offsets = octo_sensor_fan_offsets;
1624654c9735SAleksa Savic 		priv->fan_ctrl_offsets = octo_ctrl_fan_offsets;
1625d5d896b8SAleksa Savic 
1626654c9735SAleksa Savic 		priv->num_temp_sensors = OCTO_NUM_SENSORS;
1627654c9735SAleksa Savic 		priv->temp_sensor_start_offset = OCTO_SENSOR_START;
1628e2769f5eSAleksa Savic 		priv->num_virtual_temp_sensors = OCTO_NUM_VIRTUAL_SENSORS;
1629e2769f5eSAleksa Savic 		priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START;
1630662d20b3SAleksa Savic 		priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET;
1631752b9279SAleksa Savic 
1632d5d896b8SAleksa Savic 		priv->buffer_size = OCTO_CTRL_REPORT_SIZE;
1633*56b930dcSAleksa Savic 		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
1634d5d896b8SAleksa Savic 
1635d5d896b8SAleksa Savic 		priv->power_cycle_count_offset = OCTO_POWER_CYCLES;
1636d5d896b8SAleksa Savic 
1637752b9279SAleksa Savic 		priv->temp_label = label_temp_sensors;
1638e2769f5eSAleksa Savic 		priv->virtual_temp_label = label_virtual_temp_sensors;
1639752b9279SAleksa Savic 		priv->speed_label = label_fan_speed;
1640752b9279SAleksa Savic 		priv->power_label = label_fan_power;
1641752b9279SAleksa Savic 		priv->voltage_label = label_fan_voltage;
1642752b9279SAleksa Savic 		priv->current_label = label_fan_current;
16432fd3eec1SAleksa Savic 		break;
1644cdbe34daSAleksa Savic 	case USB_PRODUCT_ID_QUADRO:
1645cdbe34daSAleksa Savic 		priv->kind = quadro;
1646cdbe34daSAleksa Savic 
1647cdbe34daSAleksa Savic 		priv->num_fans = QUADRO_NUM_FANS;
1648cdbe34daSAleksa Savic 		priv->fan_sensor_offsets = quadro_sensor_fan_offsets;
1649cdbe34daSAleksa Savic 		priv->fan_ctrl_offsets = quadro_ctrl_fan_offsets;
1650d5d896b8SAleksa Savic 
1651cdbe34daSAleksa Savic 		priv->num_temp_sensors = QUADRO_NUM_SENSORS;
1652cdbe34daSAleksa Savic 		priv->temp_sensor_start_offset = QUADRO_SENSOR_START;
1653e2769f5eSAleksa Savic 		priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS;
1654e2769f5eSAleksa Savic 		priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START;
1655a2ba7ee2SLeonard Anderweit 		priv->num_flow_sensors = QUADRO_NUM_FLOW_SENSORS;
1656a2ba7ee2SLeonard Anderweit 		priv->flow_sensors_start_offset = QUADRO_FLOW_SENSOR_OFFSET;
1657a2ba7ee2SLeonard Anderweit 
1658662d20b3SAleksa Savic 		priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;
1659cdbe34daSAleksa Savic 
1660d5d896b8SAleksa Savic 		priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
1661*56b930dcSAleksa Savic 		priv->ctrl_report_delay = CTRL_REPORT_DELAY;
1662d5d896b8SAleksa Savic 
16636ff838f2SAleksa Savic 		priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
1664d5d896b8SAleksa Savic 		priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
1665d5d896b8SAleksa Savic 
1666cdbe34daSAleksa Savic 		priv->temp_label = label_temp_sensors;
1667e2769f5eSAleksa Savic 		priv->virtual_temp_label = label_virtual_temp_sensors;
1668cdbe34daSAleksa Savic 		priv->speed_label = label_quadro_speeds;
1669cdbe34daSAleksa Savic 		priv->power_label = label_fan_power;
1670cdbe34daSAleksa Savic 		priv->voltage_label = label_fan_voltage;
1671cdbe34daSAleksa Savic 		priv->current_label = label_fan_current;
1672cdbe34daSAleksa Savic 		break;
1673aed80bb9SAleksa Savic 	case USB_PRODUCT_ID_HIGHFLOWNEXT:
1674aed80bb9SAleksa Savic 		priv->kind = highflownext;
1675aed80bb9SAleksa Savic 
1676aed80bb9SAleksa Savic 		priv->num_fans = 0;
1677d5d896b8SAleksa Savic 
1678aed80bb9SAleksa Savic 		priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS;
1679aed80bb9SAleksa Savic 		priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START;
1680a2ba7ee2SLeonard Anderweit 		priv->num_flow_sensors = HIGHFLOWNEXT_NUM_FLOW_SENSORS;
1681a2ba7ee2SLeonard Anderweit 		priv->flow_sensors_start_offset = HIGHFLOWNEXT_FLOW;
1682d5d896b8SAleksa Savic 
1683aed80bb9SAleksa Savic 		priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
1684aed80bb9SAleksa Savic 
1685aed80bb9SAleksa Savic 		priv->temp_label = label_highflownext_temp_sensors;
1686aed80bb9SAleksa Savic 		priv->speed_label = label_highflownext_fan_speed;
1687aed80bb9SAleksa Savic 		priv->power_label = label_highflownext_power;
1688aed80bb9SAleksa Savic 		priv->voltage_label = label_highflownext_voltage;
1689aed80bb9SAleksa Savic 		break;
1690b3d3be6cSAleksa Savic 	case USB_PRODUCT_ID_LEAKSHIELD:
1691b3d3be6cSAleksa Savic 		/*
1692b3d3be6cSAleksa Savic 		 * Choose the right Leakshield device, because
1693b3d3be6cSAleksa Savic 		 * the other one acts as a keyboard
1694b3d3be6cSAleksa Savic 		 */
1695b3d3be6cSAleksa Savic 		if (hdev->type != 2) {
1696b3d3be6cSAleksa Savic 			ret = -ENODEV;
1697b3d3be6cSAleksa Savic 			goto fail_and_close;
1698b3d3be6cSAleksa Savic 		}
1699b3d3be6cSAleksa Savic 
1700b3d3be6cSAleksa Savic 		priv->kind = leakshield;
1701b3d3be6cSAleksa Savic 
1702b3d3be6cSAleksa Savic 		priv->num_fans = 0;
1703b3d3be6cSAleksa Savic 		priv->num_temp_sensors = LEAKSHIELD_NUM_SENSORS;
1704b3d3be6cSAleksa Savic 		priv->temp_sensor_start_offset = LEAKSHIELD_TEMPERATURE_1;
1705b3d3be6cSAleksa Savic 
1706b3d3be6cSAleksa Savic 		priv->temp_label = label_leakshield_temp_sensors;
1707b3d3be6cSAleksa Savic 		priv->speed_label = label_leakshield_fan_speed;
1708b3d3be6cSAleksa Savic 		break;
170919692f17SAleksa Savic 	case USB_PRODUCT_ID_AQUASTREAMXT:
171019692f17SAleksa Savic 		priv->kind = aquastreamxt;
171119692f17SAleksa Savic 
171219692f17SAleksa Savic 		priv->num_fans = AQUASTREAMXT_NUM_FANS;
171319692f17SAleksa Savic 		priv->fan_sensor_offsets = aquastreamxt_sensor_fan_offsets;
171419692f17SAleksa Savic 
171519692f17SAleksa Savic 		priv->num_temp_sensors = AQUASTREAMXT_NUM_SENSORS;
171619692f17SAleksa Savic 		priv->temp_sensor_start_offset = AQUASTREAMXT_SENSOR_START;
171719692f17SAleksa Savic 		priv->buffer_size = AQUASTREAMXT_SENSOR_REPORT_SIZE;
171819692f17SAleksa Savic 
171919692f17SAleksa Savic 		priv->temp_label = label_aquastreamxt_temp_sensors;
172019692f17SAleksa Savic 		priv->speed_label = label_d5next_speeds;
172119692f17SAleksa Savic 		priv->voltage_label = label_d5next_voltages;
172219692f17SAleksa Savic 		priv->current_label = label_d5next_current;
172319692f17SAleksa Savic 		break;
17247505dab7SAleksa Savic 	case USB_PRODUCT_ID_AQUASTREAMULT:
17257505dab7SAleksa Savic 		priv->kind = aquastreamult;
17267505dab7SAleksa Savic 
17277505dab7SAleksa Savic 		priv->num_fans = AQUASTREAMULT_NUM_FANS;
17287505dab7SAleksa Savic 		priv->fan_sensor_offsets = aquastreamult_sensor_fan_offsets;
17297505dab7SAleksa Savic 
17307505dab7SAleksa Savic 		priv->num_temp_sensors = AQUASTREAMULT_NUM_SENSORS;
17317505dab7SAleksa Savic 		priv->temp_sensor_start_offset = AQUASTREAMULT_SENSOR_START;
17327505dab7SAleksa Savic 
17337505dab7SAleksa Savic 		priv->temp_label = label_aquastreamult_temp;
17347505dab7SAleksa Savic 		priv->speed_label = label_aquastreamult_speeds;
17357505dab7SAleksa Savic 		priv->power_label = label_aquastreamult_power;
17367505dab7SAleksa Savic 		priv->voltage_label = label_aquastreamult_voltages;
17377505dab7SAleksa Savic 		priv->current_label = label_aquastreamult_current;
17387505dab7SAleksa Savic 		break;
1739e0f6c370SAleksa Savic 	case USB_PRODUCT_ID_POWERADJUST3:
1740e0f6c370SAleksa Savic 		priv->kind = poweradjust3;
1741e0f6c370SAleksa Savic 
1742e0f6c370SAleksa Savic 		priv->num_fans = 0;
1743e0f6c370SAleksa Savic 
1744e0f6c370SAleksa Savic 		priv->num_temp_sensors = POWERADJUST3_NUM_SENSORS;
1745e0f6c370SAleksa Savic 		priv->temp_sensor_start_offset = POWERADJUST3_SENSOR_START;
1746e0f6c370SAleksa Savic 		priv->buffer_size = POWERADJUST3_SENSOR_REPORT_SIZE;
1747e0f6c370SAleksa Savic 
1748e0f6c370SAleksa Savic 		priv->temp_label = label_poweradjust3_temp_sensors;
1749e0f6c370SAleksa Savic 		break;
17502fd3eec1SAleksa Savic 	default:
17512fd3eec1SAleksa Savic 		break;
17522fd3eec1SAleksa Savic 	}
17532fd3eec1SAleksa Savic 
17542c552111SLeonard Anderweit 	switch (priv->kind) {
17552c552111SLeonard Anderweit 	case aquaero:
17562c552111SLeonard Anderweit 		priv->serial_number_start_offset = AQUAERO_SERIAL_START;
17572c552111SLeonard Anderweit 		priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION;
17582c552111SLeonard Anderweit 
17592c552111SLeonard Anderweit 		priv->fan_structure = &aqc_aquaero_fan_structure;
17606c83ccb1SLeonard Anderweit 
17616c83ccb1SLeonard Anderweit 		priv->ctrl_report_id = AQUAERO_CTRL_REPORT_ID;
17626c83ccb1SLeonard Anderweit 		priv->secondary_ctrl_report_id = AQUAERO_SECONDARY_CTRL_REPORT_ID;
17636c83ccb1SLeonard Anderweit 		priv->secondary_ctrl_report_size = AQUAERO_SECONDARY_CTRL_REPORT_SIZE;
17646c83ccb1SLeonard Anderweit 		priv->secondary_ctrl_report = aquaero_secondary_ctrl_report;
17652c552111SLeonard Anderweit 		break;
1766e0f6c370SAleksa Savic 	case poweradjust3:
1767e0f6c370SAleksa Savic 		priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID;
1768e0f6c370SAleksa Savic 		break;
176919692f17SAleksa Savic 	case aquastreamxt:
177019692f17SAleksa Savic 		priv->serial_number_start_offset = AQUASTREAMXT_SERIAL_START;
177119692f17SAleksa Savic 		priv->firmware_version_offset = AQUASTREAMXT_FIRMWARE_VERSION;
177219692f17SAleksa Savic 
177319692f17SAleksa Savic 		priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID;
177419692f17SAleksa Savic 		break;
17752c552111SLeonard Anderweit 	default:
1776ad2f0811SLeonard Anderweit 		priv->serial_number_start_offset = AQC_SERIAL_START;
1777ad2f0811SLeonard Anderweit 		priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
1778ad2f0811SLeonard Anderweit 
1779b29090baSLeonard Anderweit 		priv->ctrl_report_id = CTRL_REPORT_ID;
1780b29090baSLeonard Anderweit 		priv->secondary_ctrl_report_id = SECONDARY_CTRL_REPORT_ID;
1781b29090baSLeonard Anderweit 		priv->secondary_ctrl_report_size = SECONDARY_CTRL_REPORT_SIZE;
1782b29090baSLeonard Anderweit 		priv->secondary_ctrl_report = secondary_ctrl_report;
1783b29090baSLeonard Anderweit 
17847505dab7SAleksa Savic 		if (priv->kind == aquastreamult)
17857505dab7SAleksa Savic 			priv->fan_structure = &aqc_aquastreamult_fan_structure;
17867505dab7SAleksa Savic 		else
1787249c7521SLeonard Anderweit 			priv->fan_structure = &aqc_general_fan_structure;
17882c552111SLeonard Anderweit 		break;
17892c552111SLeonard Anderweit 	}
1790249c7521SLeonard Anderweit 
1791654c9735SAleksa Savic 	if (priv->buffer_size != 0) {
1792654c9735SAleksa Savic 		priv->checksum_start = 0x01;
1793654c9735SAleksa Savic 		priv->checksum_length = priv->buffer_size - 3;
1794654c9735SAleksa Savic 		priv->checksum_offset = priv->buffer_size - 2;
1795654c9735SAleksa Savic 	}
1796654c9735SAleksa Savic 
17972fd3eec1SAleksa Savic 	priv->name = aqc_device_names[priv->kind];
17982fd3eec1SAleksa Savic 
1799752b9279SAleksa Savic 	priv->buffer = devm_kzalloc(&hdev->dev, priv->buffer_size, GFP_KERNEL);
18008877ecb0SChristophe JAILLET 	if (!priv->buffer) {
18018877ecb0SChristophe JAILLET 		ret = -ENOMEM;
18028877ecb0SChristophe JAILLET 		goto fail_and_close;
18038877ecb0SChristophe JAILLET 	}
1804752b9279SAleksa Savic 
1805752b9279SAleksa Savic 	mutex_init(&priv->mutex);
1806752b9279SAleksa Savic 
18072fd3eec1SAleksa Savic 	priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv,
18082fd3eec1SAleksa Savic 							  &aqc_chip_info, NULL);
18090e35f63fSAleksa Savic 
18100e35f63fSAleksa Savic 	if (IS_ERR(priv->hwmon_dev)) {
18110e35f63fSAleksa Savic 		ret = PTR_ERR(priv->hwmon_dev);
18120e35f63fSAleksa Savic 		goto fail_and_close;
18130e35f63fSAleksa Savic 	}
18140e35f63fSAleksa Savic 
18152fd3eec1SAleksa Savic 	aqc_debugfs_init(priv);
18160e35f63fSAleksa Savic 
18170e35f63fSAleksa Savic 	return 0;
18180e35f63fSAleksa Savic 
18190e35f63fSAleksa Savic fail_and_close:
18200e35f63fSAleksa Savic 	hid_hw_close(hdev);
18210e35f63fSAleksa Savic fail_and_stop:
18220e35f63fSAleksa Savic 	hid_hw_stop(hdev);
18230e35f63fSAleksa Savic 	return ret;
18240e35f63fSAleksa Savic }
18250e35f63fSAleksa Savic 
aqc_remove(struct hid_device * hdev)18262fd3eec1SAleksa Savic static void aqc_remove(struct hid_device *hdev)
18270e35f63fSAleksa Savic {
18282fd3eec1SAleksa Savic 	struct aqc_data *priv = hid_get_drvdata(hdev);
18290e35f63fSAleksa Savic 
18300e35f63fSAleksa Savic 	debugfs_remove_recursive(priv->debugfs);
18310e35f63fSAleksa Savic 	hwmon_device_unregister(priv->hwmon_dev);
18320e35f63fSAleksa Savic 
18330e35f63fSAleksa Savic 	hid_hw_close(hdev);
18340e35f63fSAleksa Savic 	hid_hw_stop(hdev);
18350e35f63fSAleksa Savic }
18360e35f63fSAleksa Savic 
18372fd3eec1SAleksa Savic static const struct hid_device_id aqc_table[] = {
18382c552111SLeonard Anderweit 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUAERO) },
18392fd3eec1SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) },
1840229b159cSJack Doan 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) },
18412fd3eec1SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },
1842752b9279SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
1843cdbe34daSAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
1844aed80bb9SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) },
1845b3d3be6cSAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_LEAKSHIELD) },
184619692f17SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) },
18477505dab7SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
1848e0f6c370SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
18492fd3eec1SAleksa Savic 	{ }
18500e35f63fSAleksa Savic };
18510e35f63fSAleksa Savic 
18522fd3eec1SAleksa Savic MODULE_DEVICE_TABLE(hid, aqc_table);
18530e35f63fSAleksa Savic 
18542fd3eec1SAleksa Savic static struct hid_driver aqc_driver = {
18550e35f63fSAleksa Savic 	.name = DRIVER_NAME,
18562fd3eec1SAleksa Savic 	.id_table = aqc_table,
18572fd3eec1SAleksa Savic 	.probe = aqc_probe,
18582fd3eec1SAleksa Savic 	.remove = aqc_remove,
18592fd3eec1SAleksa Savic 	.raw_event = aqc_raw_event,
18600e35f63fSAleksa Savic };
18610e35f63fSAleksa Savic 
aqc_init(void)18622fd3eec1SAleksa Savic static int __init aqc_init(void)
18630e35f63fSAleksa Savic {
18642fd3eec1SAleksa Savic 	return hid_register_driver(&aqc_driver);
18650e35f63fSAleksa Savic }
18660e35f63fSAleksa Savic 
aqc_exit(void)18672fd3eec1SAleksa Savic static void __exit aqc_exit(void)
18680e35f63fSAleksa Savic {
18692fd3eec1SAleksa Savic 	hid_unregister_driver(&aqc_driver);
18700e35f63fSAleksa Savic }
18710e35f63fSAleksa Savic 
18720e35f63fSAleksa Savic /* Request to initialize after the HID bus to ensure it's not being loaded before */
18732fd3eec1SAleksa Savic late_initcall(aqc_init);
18742fd3eec1SAleksa Savic module_exit(aqc_exit);
18750e35f63fSAleksa Savic 
18760e35f63fSAleksa Savic MODULE_LICENSE("GPL");
18770e35f63fSAleksa Savic MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
1878229b159cSJack Doan MODULE_AUTHOR("Jack Doan <me@jackdoan.com>");
18792fd3eec1SAleksa Savic MODULE_DESCRIPTION("Hwmon driver for Aquacomputer devices");
1880