Commit | Line | Data |
---|---|---|
74ba9207 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
84f1e442 | 2 | /* |
f58c44e6 BG |
3 | * f75375s.c - driver for the Fintek F75375/SP, F75373 and |
4 | * F75387SG/RG hardware monitoring features | |
b26e0ed4 | 5 | * Copyright (C) 2006-2007 Riku Voipio |
84f1e442 RV |
6 | * |
7 | * Datasheets available at: | |
8 | * | |
9 | * f75375: | |
4fd826ef | 10 | * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf |
84f1e442 RV |
11 | * |
12 | * f75373: | |
631dd1a8 | 13 | * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf |
84f1e442 | 14 | * |
f58c44e6 BG |
15 | * f75387: |
16 | * http://www.fintek.com.tw/files/productfiles/F75387_V027P.pdf | |
84f1e442 RV |
17 | */ |
18 | ||
19 | #include <linux/module.h> | |
20 | #include <linux/jiffies.h> | |
21 | #include <linux/hwmon.h> | |
22 | #include <linux/hwmon-sysfs.h> | |
23 | #include <linux/i2c.h> | |
24 | #include <linux/err.h> | |
25 | #include <linux/mutex.h> | |
ff312d07 | 26 | #include <linux/f75375s.h> |
5a0e3ad6 | 27 | #include <linux/slab.h> |
84f1e442 RV |
28 | |
29 | /* Addresses to scan */ | |
25e9c86d | 30 | static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; |
84f1e442 | 31 | |
f58c44e6 | 32 | enum chips { f75373, f75375, f75387 }; |
84f1e442 RV |
33 | |
34 | /* Fintek F75375 registers */ | |
35 | #define F75375_REG_CONFIG0 0x0 | |
36 | #define F75375_REG_CONFIG1 0x1 | |
37 | #define F75375_REG_CONFIG2 0x2 | |
38 | #define F75375_REG_CONFIG3 0x3 | |
39 | #define F75375_REG_ADDR 0x4 | |
40 | #define F75375_REG_INTR 0x31 | |
41 | #define F75375_CHIP_ID 0x5A | |
42 | #define F75375_REG_VERSION 0x5C | |
43 | #define F75375_REG_VENDOR 0x5D | |
44 | #define F75375_REG_FAN_TIMER 0x60 | |
45 | ||
46 | #define F75375_REG_VOLT(nr) (0x10 + (nr)) | |
47 | #define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2) | |
48 | #define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2) | |
49 | ||
50 | #define F75375_REG_TEMP(nr) (0x14 + (nr)) | |
f58c44e6 | 51 | #define F75387_REG_TEMP11_LSB(nr) (0x1a + (nr)) |
84f1e442 RV |
52 | #define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2) |
53 | #define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2) | |
54 | ||
55 | #define F75375_REG_FAN(nr) (0x16 + (nr) * 2) | |
56 | #define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2) | |
57 | #define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10) | |
58 | #define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10) | |
59 | #define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10) | |
60 | ||
61 | #define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10) | |
62 | #define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step)) | |
63 | #define F75375_REG_FAN_B_SPEED(nr, step) \ | |
64 | ((0xA5 + (nr) * 0x10) + (step) * 2) | |
65 | ||
66 | #define F75375_REG_PWM1_RAISE_DUTY 0x69 | |
67 | #define F75375_REG_PWM2_RAISE_DUTY 0x6A | |
68 | #define F75375_REG_PWM1_DROP_DUTY 0x6B | |
69 | #define F75375_REG_PWM2_DROP_DUTY 0x6C | |
70 | ||
f58c44e6 BG |
71 | #define F75375_FAN_CTRL_LINEAR(nr) (4 + nr) |
72 | #define F75387_FAN_CTRL_LINEAR(nr) (1 + ((nr) * 4)) | |
96f36408 | 73 | #define FAN_CTRL_MODE(nr) (4 + ((nr) * 2)) |
f58c44e6 BG |
74 | #define F75387_FAN_DUTY_MODE(nr) (2 + ((nr) * 4)) |
75 | #define F75387_FAN_MANU_MODE(nr) ((nr) * 4) | |
84f1e442 RV |
76 | |
77 | /* | |
78 | * Data structures and manipulation thereof | |
79 | */ | |
80 | ||
81 | struct f75375_data { | |
82 | unsigned short addr; | |
1beeffe4 | 83 | struct device *hwmon_dev; |
84f1e442 RV |
84 | |
85 | const char *name; | |
86 | int kind; | |
87 | struct mutex update_lock; /* protect register access */ | |
88 | char valid; | |
89 | unsigned long last_updated; /* In jiffies */ | |
90 | unsigned long last_limits; /* In jiffies */ | |
91 | ||
92 | /* Register values */ | |
93 | u8 in[4]; | |
94 | u8 in_max[4]; | |
95 | u8 in_min[4]; | |
96 | u16 fan[2]; | |
97 | u16 fan_min[2]; | |
740f6be3 GR |
98 | u16 fan_max[2]; |
99 | u16 fan_target[2]; | |
84f1e442 RV |
100 | u8 fan_timer; |
101 | u8 pwm[2]; | |
102 | u8 pwm_mode[2]; | |
103 | u8 pwm_enable[2]; | |
f58c44e6 BG |
104 | /* |
105 | * f75387: For remote temperature reading, it uses signed 11-bit | |
106 | * values with LSB = 0.125 degree Celsius, left-justified in 16-bit | |
107 | * registers. For original 8-bit temp readings, the LSB just is 0. | |
108 | */ | |
109 | s16 temp11[2]; | |
84f1e442 RV |
110 | s8 temp_high[2]; |
111 | s8 temp_max_hyst[2]; | |
112 | }; | |
113 | ||
310ec792 | 114 | static int f75375_detect(struct i2c_client *client, |
935ada8c | 115 | struct i2c_board_info *info); |
d2653e92 JD |
116 | static int f75375_probe(struct i2c_client *client, |
117 | const struct i2c_device_id *id); | |
620c142d | 118 | static int f75375_remove(struct i2c_client *client); |
84f1e442 | 119 | |
3760f736 JD |
120 | static const struct i2c_device_id f75375_id[] = { |
121 | { "f75373", f75373 }, | |
122 | { "f75375", f75375 }, | |
f58c44e6 | 123 | { "f75387", f75387 }, |
3760f736 JD |
124 | { } |
125 | }; | |
126 | MODULE_DEVICE_TABLE(i2c, f75375_id); | |
127 | ||
620c142d | 128 | static struct i2c_driver f75375_driver = { |
935ada8c | 129 | .class = I2C_CLASS_HWMON, |
620c142d RV |
130 | .driver = { |
131 | .name = "f75375", | |
132 | }, | |
133 | .probe = f75375_probe, | |
134 | .remove = f75375_remove, | |
3760f736 | 135 | .id_table = f75375_id, |
935ada8c | 136 | .detect = f75375_detect, |
c3813d6a | 137 | .address_list = normal_i2c, |
620c142d RV |
138 | }; |
139 | ||
84f1e442 RV |
140 | static inline int f75375_read8(struct i2c_client *client, u8 reg) |
141 | { | |
142 | return i2c_smbus_read_byte_data(client, reg); | |
143 | } | |
144 | ||
145 | /* in most cases, should be called while holding update_lock */ | |
146 | static inline u16 f75375_read16(struct i2c_client *client, u8 reg) | |
147 | { | |
4fd826ef GR |
148 | return (i2c_smbus_read_byte_data(client, reg) << 8) |
149 | | i2c_smbus_read_byte_data(client, reg + 1); | |
84f1e442 RV |
150 | } |
151 | ||
152 | static inline void f75375_write8(struct i2c_client *client, u8 reg, | |
153 | u8 value) | |
154 | { | |
155 | i2c_smbus_write_byte_data(client, reg, value); | |
156 | } | |
157 | ||
158 | static inline void f75375_write16(struct i2c_client *client, u8 reg, | |
159 | u16 value) | |
160 | { | |
eb2f255b | 161 | int err = i2c_smbus_write_byte_data(client, reg, (value >> 8)); |
84f1e442 RV |
162 | if (err) |
163 | return; | |
164 | i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); | |
165 | } | |
166 | ||
331255d3 NS |
167 | static void f75375_write_pwm(struct i2c_client *client, int nr) |
168 | { | |
169 | struct f75375_data *data = i2c_get_clientdata(client); | |
170 | if (data->kind == f75387) | |
171 | f75375_write16(client, F75375_REG_FAN_EXP(nr), data->pwm[nr]); | |
172 | else | |
173 | f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), | |
174 | data->pwm[nr]); | |
175 | } | |
176 | ||
84f1e442 RV |
177 | static struct f75375_data *f75375_update_device(struct device *dev) |
178 | { | |
179 | struct i2c_client *client = to_i2c_client(dev); | |
180 | struct f75375_data *data = i2c_get_clientdata(client); | |
181 | int nr; | |
182 | ||
183 | mutex_lock(&data->update_lock); | |
184 | ||
185 | /* Limit registers cache is refreshed after 60 seconds */ | |
186 | if (time_after(jiffies, data->last_limits + 60 * HZ) | |
187 | || !data->valid) { | |
188 | for (nr = 0; nr < 2; nr++) { | |
189 | data->temp_high[nr] = | |
190 | f75375_read8(client, F75375_REG_TEMP_HIGH(nr)); | |
191 | data->temp_max_hyst[nr] = | |
192 | f75375_read8(client, F75375_REG_TEMP_HYST(nr)); | |
740f6be3 | 193 | data->fan_max[nr] = |
84f1e442 RV |
194 | f75375_read16(client, F75375_REG_FAN_FULL(nr)); |
195 | data->fan_min[nr] = | |
196 | f75375_read16(client, F75375_REG_FAN_MIN(nr)); | |
740f6be3 | 197 | data->fan_target[nr] = |
84f1e442 | 198 | f75375_read16(client, F75375_REG_FAN_EXP(nr)); |
84f1e442 RV |
199 | } |
200 | for (nr = 0; nr < 4; nr++) { | |
201 | data->in_max[nr] = | |
202 | f75375_read8(client, F75375_REG_VOLT_HIGH(nr)); | |
203 | data->in_min[nr] = | |
204 | f75375_read8(client, F75375_REG_VOLT_LOW(nr)); | |
205 | } | |
206 | data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER); | |
207 | data->last_limits = jiffies; | |
208 | } | |
209 | ||
210 | /* Measurement registers cache is refreshed after 2 second */ | |
211 | if (time_after(jiffies, data->last_updated + 2 * HZ) | |
212 | || !data->valid) { | |
213 | for (nr = 0; nr < 2; nr++) { | |
a1c1baf0 NS |
214 | data->pwm[nr] = f75375_read8(client, |
215 | F75375_REG_FAN_PWM_DUTY(nr)); | |
f58c44e6 BG |
216 | /* assign MSB, therefore shift it by 8 bits */ |
217 | data->temp11[nr] = | |
218 | f75375_read8(client, F75375_REG_TEMP(nr)) << 8; | |
219 | if (data->kind == f75387) | |
220 | /* merge F75387's temperature LSB (11-bit) */ | |
221 | data->temp11[nr] |= | |
222 | f75375_read8(client, | |
223 | F75387_REG_TEMP11_LSB(nr)); | |
84f1e442 RV |
224 | data->fan[nr] = |
225 | f75375_read16(client, F75375_REG_FAN(nr)); | |
226 | } | |
227 | for (nr = 0; nr < 4; nr++) | |
228 | data->in[nr] = | |
229 | f75375_read8(client, F75375_REG_VOLT(nr)); | |
230 | ||
231 | data->last_updated = jiffies; | |
232 | data->valid = 1; | |
233 | } | |
234 | ||
235 | mutex_unlock(&data->update_lock); | |
236 | return data; | |
237 | } | |
238 | ||
239 | static inline u16 rpm_from_reg(u16 reg) | |
240 | { | |
241 | if (reg == 0 || reg == 0xffff) | |
242 | return 0; | |
4fd826ef | 243 | return 1500000 / reg; |
84f1e442 RV |
244 | } |
245 | ||
246 | static inline u16 rpm_to_reg(int rpm) | |
247 | { | |
248 | if (rpm < 367 || rpm > 0xffff) | |
249 | return 0xffff; | |
4fd826ef | 250 | return 1500000 / rpm; |
84f1e442 RV |
251 | } |
252 | ||
b17d6561 NS |
253 | static bool duty_mode_enabled(u8 pwm_enable) |
254 | { | |
255 | switch (pwm_enable) { | |
256 | case 0: /* Manual, duty mode (full speed) */ | |
257 | case 1: /* Manual, duty mode */ | |
258 | case 4: /* Auto, duty mode */ | |
259 | return true; | |
260 | case 2: /* Auto, speed mode */ | |
261 | case 3: /* Manual, speed mode */ | |
262 | return false; | |
263 | default: | |
39b103b4 | 264 | WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); |
6394011d | 265 | return true; |
b17d6561 NS |
266 | } |
267 | } | |
268 | ||
15d1ad0c NS |
269 | static bool auto_mode_enabled(u8 pwm_enable) |
270 | { | |
271 | switch (pwm_enable) { | |
272 | case 0: /* Manual, duty mode (full speed) */ | |
273 | case 1: /* Manual, duty mode */ | |
274 | case 3: /* Manual, speed mode */ | |
275 | return false; | |
276 | case 2: /* Auto, speed mode */ | |
277 | case 4: /* Auto, duty mode */ | |
278 | return true; | |
279 | default: | |
39b103b4 | 280 | WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); |
6394011d | 281 | return false; |
15d1ad0c NS |
282 | } |
283 | } | |
284 | ||
84f1e442 RV |
285 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, |
286 | const char *buf, size_t count) | |
287 | { | |
288 | int nr = to_sensor_dev_attr(attr)->index; | |
289 | struct i2c_client *client = to_i2c_client(dev); | |
290 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
291 | unsigned long val; |
292 | int err; | |
293 | ||
294 | err = kstrtoul(buf, 10, &val); | |
295 | if (err < 0) | |
296 | return err; | |
84f1e442 RV |
297 | |
298 | mutex_lock(&data->update_lock); | |
299 | data->fan_min[nr] = rpm_to_reg(val); | |
300 | f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]); | |
301 | mutex_unlock(&data->update_lock); | |
302 | return count; | |
303 | } | |
304 | ||
740f6be3 | 305 | static ssize_t set_fan_target(struct device *dev, struct device_attribute *attr, |
84f1e442 RV |
306 | const char *buf, size_t count) |
307 | { | |
308 | int nr = to_sensor_dev_attr(attr)->index; | |
309 | struct i2c_client *client = to_i2c_client(dev); | |
310 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
311 | unsigned long val; |
312 | int err; | |
313 | ||
314 | err = kstrtoul(buf, 10, &val); | |
315 | if (err < 0) | |
316 | return err; | |
84f1e442 | 317 | |
15d1ad0c NS |
318 | if (auto_mode_enabled(data->pwm_enable[nr])) |
319 | return -EINVAL; | |
320 | if (data->kind == f75387 && duty_mode_enabled(data->pwm_enable[nr])) | |
321 | return -EINVAL; | |
322 | ||
84f1e442 | 323 | mutex_lock(&data->update_lock); |
740f6be3 GR |
324 | data->fan_target[nr] = rpm_to_reg(val); |
325 | f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_target[nr]); | |
84f1e442 RV |
326 | mutex_unlock(&data->update_lock); |
327 | return count; | |
328 | } | |
329 | ||
330 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | |
331 | const char *buf, size_t count) | |
332 | { | |
333 | int nr = to_sensor_dev_attr(attr)->index; | |
334 | struct i2c_client *client = to_i2c_client(dev); | |
335 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
336 | unsigned long val; |
337 | int err; | |
338 | ||
339 | err = kstrtoul(buf, 10, &val); | |
340 | if (err < 0) | |
341 | return err; | |
84f1e442 | 342 | |
15d1ad0c NS |
343 | if (auto_mode_enabled(data->pwm_enable[nr]) || |
344 | !duty_mode_enabled(data->pwm_enable[nr])) | |
345 | return -EINVAL; | |
346 | ||
84f1e442 | 347 | mutex_lock(&data->update_lock); |
2a844c14 | 348 | data->pwm[nr] = clamp_val(val, 0, 255); |
331255d3 | 349 | f75375_write_pwm(client, nr); |
84f1e442 RV |
350 | mutex_unlock(&data->update_lock); |
351 | return count; | |
352 | } | |
353 | ||
354 | static ssize_t show_pwm_enable(struct device *dev, struct device_attribute | |
355 | *attr, char *buf) | |
356 | { | |
357 | int nr = to_sensor_dev_attr(attr)->index; | |
358 | struct f75375_data *data = f75375_update_device(dev); | |
359 | return sprintf(buf, "%d\n", data->pwm_enable[nr]); | |
360 | } | |
361 | ||
ff312d07 | 362 | static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) |
84f1e442 | 363 | { |
84f1e442 | 364 | struct f75375_data *data = i2c_get_clientdata(client); |
84f1e442 RV |
365 | u8 fanmode; |
366 | ||
b17d6561 | 367 | if (val < 0 || val > 4) |
84f1e442 RV |
368 | return -EINVAL; |
369 | ||
84f1e442 | 370 | fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); |
f58c44e6 | 371 | if (data->kind == f75387) { |
b17d6561 NS |
372 | /* For now, deny dangerous toggling of duty mode */ |
373 | if (duty_mode_enabled(data->pwm_enable[nr]) != | |
374 | duty_mode_enabled(val)) | |
375 | return -EOPNOTSUPP; | |
f58c44e6 BG |
376 | /* clear each fanX_mode bit before setting them properly */ |
377 | fanmode &= ~(1 << F75387_FAN_DUTY_MODE(nr)); | |
378 | fanmode &= ~(1 << F75387_FAN_MANU_MODE(nr)); | |
379 | switch (val) { | |
380 | case 0: /* full speed */ | |
381 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | |
382 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | |
383 | data->pwm[nr] = 255; | |
f58c44e6 BG |
384 | break; |
385 | case 1: /* PWM */ | |
386 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | |
387 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | |
388 | break; | |
b17d6561 | 389 | case 2: /* Automatic, speed mode */ |
f58c44e6 BG |
390 | break; |
391 | case 3: /* fan speed */ | |
392 | fanmode |= (1 << F75387_FAN_MANU_MODE(nr)); | |
393 | break; | |
b17d6561 NS |
394 | case 4: /* Automatic, pwm */ |
395 | fanmode |= (1 << F75387_FAN_DUTY_MODE(nr)); | |
396 | break; | |
f58c44e6 BG |
397 | } |
398 | } else { | |
399 | /* clear each fanX_mode bit before setting them properly */ | |
400 | fanmode &= ~(3 << FAN_CTRL_MODE(nr)); | |
401 | switch (val) { | |
402 | case 0: /* full speed */ | |
403 | fanmode |= (3 << FAN_CTRL_MODE(nr)); | |
404 | data->pwm[nr] = 255; | |
f58c44e6 BG |
405 | break; |
406 | case 1: /* PWM */ | |
407 | fanmode |= (3 << FAN_CTRL_MODE(nr)); | |
408 | break; | |
409 | case 2: /* AUTOMATIC*/ | |
09e87e5c | 410 | fanmode |= (1 << FAN_CTRL_MODE(nr)); |
f58c44e6 BG |
411 | break; |
412 | case 3: /* fan speed */ | |
413 | break; | |
b17d6561 NS |
414 | case 4: /* Automatic pwm */ |
415 | return -EINVAL; | |
f58c44e6 | 416 | } |
84f1e442 | 417 | } |
f58c44e6 | 418 | |
84f1e442 RV |
419 | f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); |
420 | data->pwm_enable[nr] = val; | |
c1c1a3d0 | 421 | if (val == 0) |
331255d3 | 422 | f75375_write_pwm(client, nr); |
ff312d07 RV |
423 | return 0; |
424 | } | |
425 | ||
426 | static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, | |
427 | const char *buf, size_t count) | |
428 | { | |
429 | int nr = to_sensor_dev_attr(attr)->index; | |
430 | struct i2c_client *client = to_i2c_client(dev); | |
431 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
432 | unsigned long val; |
433 | int err; | |
434 | ||
435 | err = kstrtoul(buf, 10, &val); | |
436 | if (err < 0) | |
437 | return err; | |
ff312d07 RV |
438 | |
439 | mutex_lock(&data->update_lock); | |
440 | err = set_pwm_enable_direct(client, nr, val); | |
84f1e442 | 441 | mutex_unlock(&data->update_lock); |
ff312d07 | 442 | return err ? err : count; |
84f1e442 RV |
443 | } |
444 | ||
445 | static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr, | |
446 | const char *buf, size_t count) | |
447 | { | |
448 | int nr = to_sensor_dev_attr(attr)->index; | |
449 | struct i2c_client *client = to_i2c_client(dev); | |
450 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
451 | unsigned long val; |
452 | int err; | |
453 | u8 conf; | |
f58c44e6 | 454 | char reg, ctrl; |
4fd826ef GR |
455 | |
456 | err = kstrtoul(buf, 10, &val); | |
457 | if (err < 0) | |
458 | return err; | |
84f1e442 | 459 | |
76e83bef | 460 | if (!(val == 0 || val == 1)) |
84f1e442 RV |
461 | return -EINVAL; |
462 | ||
5cd3222a GR |
463 | /* F75373 does not support DC (linear voltage) fan control mode */ |
464 | if (data->kind == f75373 && val == 0) | |
465 | return -EINVAL; | |
466 | ||
f58c44e6 BG |
467 | /* take care for different registers */ |
468 | if (data->kind == f75387) { | |
469 | reg = F75375_REG_FAN_TIMER; | |
470 | ctrl = F75387_FAN_CTRL_LINEAR(nr); | |
471 | } else { | |
472 | reg = F75375_REG_CONFIG1; | |
473 | ctrl = F75375_FAN_CTRL_LINEAR(nr); | |
474 | } | |
475 | ||
84f1e442 | 476 | mutex_lock(&data->update_lock); |
f58c44e6 BG |
477 | conf = f75375_read8(client, reg); |
478 | conf &= ~(1 << ctrl); | |
84f1e442 RV |
479 | |
480 | if (val == 0) | |
f58c44e6 | 481 | conf |= (1 << ctrl); |
84f1e442 | 482 | |
f58c44e6 | 483 | f75375_write8(client, reg, conf); |
84f1e442 RV |
484 | data->pwm_mode[nr] = val; |
485 | mutex_unlock(&data->update_lock); | |
486 | return count; | |
487 | } | |
488 | ||
489 | static ssize_t show_pwm(struct device *dev, struct device_attribute | |
490 | *attr, char *buf) | |
491 | { | |
492 | int nr = to_sensor_dev_attr(attr)->index; | |
493 | struct f75375_data *data = f75375_update_device(dev); | |
494 | return sprintf(buf, "%d\n", data->pwm[nr]); | |
495 | } | |
496 | ||
497 | static ssize_t show_pwm_mode(struct device *dev, struct device_attribute | |
498 | *attr, char *buf) | |
499 | { | |
500 | int nr = to_sensor_dev_attr(attr)->index; | |
501 | struct f75375_data *data = f75375_update_device(dev); | |
502 | return sprintf(buf, "%d\n", data->pwm_mode[nr]); | |
503 | } | |
504 | ||
505 | #define VOLT_FROM_REG(val) ((val) * 8) | |
506 | #define VOLT_TO_REG(val) ((val) / 8) | |
507 | ||
508 | static ssize_t show_in(struct device *dev, struct device_attribute *attr, | |
509 | char *buf) | |
510 | { | |
511 | int nr = to_sensor_dev_attr(attr)->index; | |
512 | struct f75375_data *data = f75375_update_device(dev); | |
513 | return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr])); | |
514 | } | |
515 | ||
516 | static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, | |
517 | char *buf) | |
518 | { | |
519 | int nr = to_sensor_dev_attr(attr)->index; | |
520 | struct f75375_data *data = f75375_update_device(dev); | |
521 | return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr])); | |
522 | } | |
523 | ||
524 | static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, | |
525 | char *buf) | |
526 | { | |
527 | int nr = to_sensor_dev_attr(attr)->index; | |
528 | struct f75375_data *data = f75375_update_device(dev); | |
529 | return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr])); | |
530 | } | |
531 | ||
532 | static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, | |
533 | const char *buf, size_t count) | |
534 | { | |
535 | int nr = to_sensor_dev_attr(attr)->index; | |
536 | struct i2c_client *client = to_i2c_client(dev); | |
537 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
538 | unsigned long val; |
539 | int err; | |
540 | ||
541 | err = kstrtoul(buf, 10, &val); | |
542 | if (err < 0) | |
543 | return err; | |
544 | ||
2a844c14 | 545 | val = clamp_val(VOLT_TO_REG(val), 0, 0xff); |
84f1e442 RV |
546 | mutex_lock(&data->update_lock); |
547 | data->in_max[nr] = val; | |
548 | f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]); | |
549 | mutex_unlock(&data->update_lock); | |
550 | return count; | |
551 | } | |
552 | ||
553 | static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, | |
554 | const char *buf, size_t count) | |
555 | { | |
556 | int nr = to_sensor_dev_attr(attr)->index; | |
557 | struct i2c_client *client = to_i2c_client(dev); | |
558 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
559 | unsigned long val; |
560 | int err; | |
561 | ||
562 | err = kstrtoul(buf, 10, &val); | |
563 | if (err < 0) | |
564 | return err; | |
565 | ||
2a844c14 | 566 | val = clamp_val(VOLT_TO_REG(val), 0, 0xff); |
84f1e442 RV |
567 | mutex_lock(&data->update_lock); |
568 | data->in_min[nr] = val; | |
569 | f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]); | |
570 | mutex_unlock(&data->update_lock); | |
571 | return count; | |
572 | } | |
573 | #define TEMP_FROM_REG(val) ((val) * 1000) | |
574 | #define TEMP_TO_REG(val) ((val) / 1000) | |
f58c44e6 | 575 | #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) |
84f1e442 | 576 | |
f58c44e6 | 577 | static ssize_t show_temp11(struct device *dev, struct device_attribute *attr, |
84f1e442 RV |
578 | char *buf) |
579 | { | |
580 | int nr = to_sensor_dev_attr(attr)->index; | |
581 | struct f75375_data *data = f75375_update_device(dev); | |
f58c44e6 | 582 | return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[nr])); |
84f1e442 RV |
583 | } |
584 | ||
585 | static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, | |
586 | char *buf) | |
587 | { | |
588 | int nr = to_sensor_dev_attr(attr)->index; | |
589 | struct f75375_data *data = f75375_update_device(dev); | |
590 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); | |
591 | } | |
592 | ||
593 | static ssize_t show_temp_max_hyst(struct device *dev, | |
594 | struct device_attribute *attr, char *buf) | |
595 | { | |
596 | int nr = to_sensor_dev_attr(attr)->index; | |
597 | struct f75375_data *data = f75375_update_device(dev); | |
598 | return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr])); | |
599 | } | |
600 | ||
601 | static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, | |
602 | const char *buf, size_t count) | |
603 | { | |
604 | int nr = to_sensor_dev_attr(attr)->index; | |
605 | struct i2c_client *client = to_i2c_client(dev); | |
606 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
607 | unsigned long val; |
608 | int err; | |
609 | ||
610 | err = kstrtoul(buf, 10, &val); | |
611 | if (err < 0) | |
612 | return err; | |
613 | ||
2a844c14 | 614 | val = clamp_val(TEMP_TO_REG(val), 0, 127); |
84f1e442 RV |
615 | mutex_lock(&data->update_lock); |
616 | data->temp_high[nr] = val; | |
617 | f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]); | |
618 | mutex_unlock(&data->update_lock); | |
619 | return count; | |
620 | } | |
621 | ||
622 | static ssize_t set_temp_max_hyst(struct device *dev, | |
623 | struct device_attribute *attr, const char *buf, size_t count) | |
624 | { | |
625 | int nr = to_sensor_dev_attr(attr)->index; | |
626 | struct i2c_client *client = to_i2c_client(dev); | |
627 | struct f75375_data *data = i2c_get_clientdata(client); | |
4fd826ef GR |
628 | unsigned long val; |
629 | int err; | |
630 | ||
631 | err = kstrtoul(buf, 10, &val); | |
632 | if (err < 0) | |
633 | return err; | |
634 | ||
2a844c14 | 635 | val = clamp_val(TEMP_TO_REG(val), 0, 127); |
84f1e442 RV |
636 | mutex_lock(&data->update_lock); |
637 | data->temp_max_hyst[nr] = val; | |
638 | f75375_write8(client, F75375_REG_TEMP_HYST(nr), | |
639 | data->temp_max_hyst[nr]); | |
640 | mutex_unlock(&data->update_lock); | |
641 | return count; | |
642 | } | |
643 | ||
644 | #define show_fan(thing) \ | |
645 | static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \ | |
646 | char *buf)\ | |
647 | {\ | |
648 | int nr = to_sensor_dev_attr(attr)->index;\ | |
649 | struct f75375_data *data = f75375_update_device(dev); \ | |
650 | return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \ | |
651 | } | |
652 | ||
653 | show_fan(fan); | |
654 | show_fan(fan_min); | |
740f6be3 GR |
655 | show_fan(fan_max); |
656 | show_fan(fan_target); | |
84f1e442 RV |
657 | |
658 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); | |
659 | static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR, | |
660 | show_in_max, set_in_max, 0); | |
661 | static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR, | |
662 | show_in_min, set_in_min, 0); | |
663 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); | |
664 | static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR, | |
665 | show_in_max, set_in_max, 1); | |
666 | static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR, | |
667 | show_in_min, set_in_min, 1); | |
668 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); | |
669 | static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR, | |
670 | show_in_max, set_in_max, 2); | |
671 | static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR, | |
672 | show_in_min, set_in_min, 2); | |
673 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); | |
674 | static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR, | |
675 | show_in_max, set_in_max, 3); | |
676 | static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR, | |
677 | show_in_min, set_in_min, 3); | |
f58c44e6 | 678 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 0); |
84f1e442 RV |
679 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, |
680 | show_temp_max_hyst, set_temp_max_hyst, 0); | |
681 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR, | |
682 | show_temp_max, set_temp_max, 0); | |
f58c44e6 | 683 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 1); |
84f1e442 RV |
684 | static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, |
685 | show_temp_max_hyst, set_temp_max_hyst, 1); | |
686 | static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR, | |
687 | show_temp_max, set_temp_max, 1); | |
688 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | |
740f6be3 | 689 | static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO, show_fan_max, NULL, 0); |
84f1e442 RV |
690 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR, |
691 | show_fan_min, set_fan_min, 0); | |
740f6be3 GR |
692 | static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO|S_IWUSR, |
693 | show_fan_target, set_fan_target, 0); | |
84f1e442 | 694 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); |
740f6be3 | 695 | static SENSOR_DEVICE_ATTR(fan2_max, S_IRUGO, show_fan_max, NULL, 1); |
84f1e442 RV |
696 | static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR, |
697 | show_fan_min, set_fan_min, 1); | |
740f6be3 GR |
698 | static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO|S_IWUSR, |
699 | show_fan_target, set_fan_target, 1); | |
84f1e442 RV |
700 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, |
701 | show_pwm, set_pwm, 0); | |
702 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, | |
703 | show_pwm_enable, set_pwm_enable, 0); | |
76e83bef | 704 | static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, |
84f1e442 RV |
705 | show_pwm_mode, set_pwm_mode, 0); |
706 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, | |
707 | show_pwm, set_pwm, 1); | |
708 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, | |
709 | show_pwm_enable, set_pwm_enable, 1); | |
76e83bef | 710 | static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, |
84f1e442 RV |
711 | show_pwm_mode, set_pwm_mode, 1); |
712 | ||
713 | static struct attribute *f75375_attributes[] = { | |
714 | &sensor_dev_attr_temp1_input.dev_attr.attr, | |
715 | &sensor_dev_attr_temp1_max.dev_attr.attr, | |
716 | &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, | |
717 | &sensor_dev_attr_temp2_input.dev_attr.attr, | |
718 | &sensor_dev_attr_temp2_max.dev_attr.attr, | |
719 | &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, | |
720 | &sensor_dev_attr_fan1_input.dev_attr.attr, | |
740f6be3 | 721 | &sensor_dev_attr_fan1_max.dev_attr.attr, |
84f1e442 | 722 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
740f6be3 | 723 | &sensor_dev_attr_fan1_target.dev_attr.attr, |
84f1e442 | 724 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
740f6be3 | 725 | &sensor_dev_attr_fan2_max.dev_attr.attr, |
84f1e442 | 726 | &sensor_dev_attr_fan2_min.dev_attr.attr, |
740f6be3 | 727 | &sensor_dev_attr_fan2_target.dev_attr.attr, |
84f1e442 RV |
728 | &sensor_dev_attr_pwm1.dev_attr.attr, |
729 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | |
730 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | |
731 | &sensor_dev_attr_pwm2.dev_attr.attr, | |
732 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | |
733 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, | |
734 | &sensor_dev_attr_in0_input.dev_attr.attr, | |
735 | &sensor_dev_attr_in0_max.dev_attr.attr, | |
736 | &sensor_dev_attr_in0_min.dev_attr.attr, | |
737 | &sensor_dev_attr_in1_input.dev_attr.attr, | |
738 | &sensor_dev_attr_in1_max.dev_attr.attr, | |
739 | &sensor_dev_attr_in1_min.dev_attr.attr, | |
740 | &sensor_dev_attr_in2_input.dev_attr.attr, | |
741 | &sensor_dev_attr_in2_max.dev_attr.attr, | |
742 | &sensor_dev_attr_in2_min.dev_attr.attr, | |
743 | &sensor_dev_attr_in3_input.dev_attr.attr, | |
744 | &sensor_dev_attr_in3_max.dev_attr.attr, | |
745 | &sensor_dev_attr_in3_min.dev_attr.attr, | |
746 | NULL | |
747 | }; | |
748 | ||
749 | static const struct attribute_group f75375_group = { | |
750 | .attrs = f75375_attributes, | |
751 | }; | |
752 | ||
ff312d07 RV |
753 | static void f75375_init(struct i2c_client *client, struct f75375_data *data, |
754 | struct f75375s_platform_data *f75375s_pdata) | |
755 | { | |
756 | int nr; | |
b1b561a2 GR |
757 | |
758 | if (!f75375s_pdata) { | |
759 | u8 conf, mode; | |
760 | int nr; | |
761 | ||
762 | conf = f75375_read8(client, F75375_REG_CONFIG1); | |
763 | mode = f75375_read8(client, F75375_REG_FAN_TIMER); | |
764 | for (nr = 0; nr < 2; nr++) { | |
f58c44e6 BG |
765 | if (data->kind == f75387) { |
766 | bool manu, duty; | |
767 | ||
a367a1e0 | 768 | if (!(mode & (1 << F75387_FAN_CTRL_LINEAR(nr)))) |
f58c44e6 BG |
769 | data->pwm_mode[nr] = 1; |
770 | ||
771 | manu = ((mode >> F75387_FAN_MANU_MODE(nr)) & 1); | |
772 | duty = ((mode >> F75387_FAN_DUTY_MODE(nr)) & 1); | |
b17d6561 NS |
773 | if (!manu && duty) |
774 | /* auto, pwm */ | |
775 | data->pwm_enable[nr] = 4; | |
776 | else if (manu && !duty) | |
777 | /* manual, speed */ | |
f58c44e6 | 778 | data->pwm_enable[nr] = 3; |
b17d6561 NS |
779 | else if (!manu && !duty) |
780 | /* automatic, speed */ | |
f58c44e6 BG |
781 | data->pwm_enable[nr] = 2; |
782 | else | |
b17d6561 | 783 | /* manual, pwm */ |
f58c44e6 BG |
784 | data->pwm_enable[nr] = 1; |
785 | } else { | |
786 | if (!(conf & (1 << F75375_FAN_CTRL_LINEAR(nr)))) | |
787 | data->pwm_mode[nr] = 1; | |
788 | ||
789 | switch ((mode >> FAN_CTRL_MODE(nr)) & 3) { | |
790 | case 0: /* speed */ | |
791 | data->pwm_enable[nr] = 3; | |
792 | break; | |
793 | case 1: /* automatic */ | |
794 | data->pwm_enable[nr] = 2; | |
795 | break; | |
796 | default: /* manual */ | |
797 | data->pwm_enable[nr] = 1; | |
798 | break; | |
799 | } | |
b1b561a2 GR |
800 | } |
801 | } | |
802 | return; | |
803 | } | |
804 | ||
ff312d07 RV |
805 | set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]); |
806 | set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]); | |
807 | for (nr = 0; nr < 2; nr++) { | |
15d1ad0c NS |
808 | if (auto_mode_enabled(f75375s_pdata->pwm_enable[nr]) || |
809 | !duty_mode_enabled(f75375s_pdata->pwm_enable[nr])) | |
810 | continue; | |
2a844c14 | 811 | data->pwm[nr] = clamp_val(f75375s_pdata->pwm[nr], 0, 255); |
331255d3 | 812 | f75375_write_pwm(client, nr); |
ff312d07 RV |
813 | } |
814 | ||
815 | } | |
816 | ||
d2653e92 JD |
817 | static int f75375_probe(struct i2c_client *client, |
818 | const struct i2c_device_id *id) | |
620c142d | 819 | { |
51b3e270 | 820 | struct f75375_data *data; |
a8b3a3a5 JH |
821 | struct f75375s_platform_data *f75375s_pdata = |
822 | dev_get_platdata(&client->dev); | |
620c142d RV |
823 | int err; |
824 | ||
825 | if (!i2c_check_functionality(client->adapter, | |
826 | I2C_FUNC_SMBUS_BYTE_DATA)) | |
827 | return -EIO; | |
05639bcb GR |
828 | data = devm_kzalloc(&client->dev, sizeof(struct f75375_data), |
829 | GFP_KERNEL); | |
4fd826ef | 830 | if (!data) |
620c142d RV |
831 | return -ENOMEM; |
832 | ||
833 | i2c_set_clientdata(client, data); | |
620c142d | 834 | mutex_init(&data->update_lock); |
3760f736 | 835 | data->kind = id->driver_data; |
620c142d | 836 | |
4fd826ef GR |
837 | err = sysfs_create_group(&client->dev.kobj, &f75375_group); |
838 | if (err) | |
05639bcb | 839 | return err; |
620c142d | 840 | |
edeea102 | 841 | if (data->kind != f75373) { |
76e83bef RV |
842 | err = sysfs_chmod_file(&client->dev.kobj, |
843 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | |
844 | S_IRUGO | S_IWUSR); | |
845 | if (err) | |
846 | goto exit_remove; | |
847 | err = sysfs_chmod_file(&client->dev.kobj, | |
848 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, | |
849 | S_IRUGO | S_IWUSR); | |
850 | if (err) | |
851 | goto exit_remove; | |
852 | } | |
853 | ||
620c142d RV |
854 | data->hwmon_dev = hwmon_device_register(&client->dev); |
855 | if (IS_ERR(data->hwmon_dev)) { | |
856 | err = PTR_ERR(data->hwmon_dev); | |
857 | goto exit_remove; | |
858 | } | |
859 | ||
b1b561a2 | 860 | f75375_init(client, data, f75375s_pdata); |
ff312d07 | 861 | |
620c142d RV |
862 | return 0; |
863 | ||
864 | exit_remove: | |
865 | sysfs_remove_group(&client->dev.kobj, &f75375_group); | |
620c142d RV |
866 | return err; |
867 | } | |
868 | ||
869 | static int f75375_remove(struct i2c_client *client) | |
870 | { | |
871 | struct f75375_data *data = i2c_get_clientdata(client); | |
872 | hwmon_device_unregister(data->hwmon_dev); | |
873 | sysfs_remove_group(&client->dev.kobj, &f75375_group); | |
84f1e442 RV |
874 | return 0; |
875 | } | |
876 | ||
935ada8c | 877 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
310ec792 | 878 | static int f75375_detect(struct i2c_client *client, |
935ada8c | 879 | struct i2c_board_info *info) |
84f1e442 | 880 | { |
935ada8c | 881 | struct i2c_adapter *adapter = client->adapter; |
52df6440 JD |
882 | u16 vendid, chipid; |
883 | u8 version; | |
884 | const char *name; | |
84f1e442 | 885 | |
52df6440 JD |
886 | vendid = f75375_read16(client, F75375_REG_VENDOR); |
887 | chipid = f75375_read16(client, F75375_CHIP_ID); | |
f58c44e6 BG |
888 | if (vendid != 0x1934) |
889 | return -ENODEV; | |
890 | ||
891 | if (chipid == 0x0306) | |
84f1e442 | 892 | name = "f75375"; |
f58c44e6 | 893 | else if (chipid == 0x0204) |
84f1e442 | 894 | name = "f75373"; |
f58c44e6 BG |
895 | else if (chipid == 0x0410) |
896 | name = "f75387"; | |
52df6440 JD |
897 | else |
898 | return -ENODEV; | |
899 | ||
900 | version = f75375_read8(client, F75375_REG_VERSION); | |
84f1e442 | 901 | dev_info(&adapter->dev, "found %s version: %02X\n", name, version); |
935ada8c | 902 | strlcpy(info->type, name, I2C_NAME_SIZE); |
84f1e442 | 903 | |
84f1e442 | 904 | return 0; |
84f1e442 RV |
905 | } |
906 | ||
f0967eea | 907 | module_i2c_driver(f75375_driver); |
84f1e442 | 908 | |
b26e0ed4 | 909 | MODULE_AUTHOR("Riku Voipio"); |
84f1e442 | 910 | MODULE_LICENSE("GPL"); |
f58c44e6 | 911 | MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver"); |