diff options
Diffstat (limited to 'drivers/hwmon/f71805f.c')
-rw-r--r-- | drivers/hwmon/f71805f.c | 569 |
1 files changed, 491 insertions, 78 deletions
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index de17a72149d9..a272cae8f60e 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -1,12 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated | 2 | * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O |
3 | * hardware monitoring features | 3 | * chips integrated hardware monitoring features |
4 | * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates | 6 | * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates |
7 | * complete hardware monitoring features: voltage, fan and temperature | 7 | * complete hardware monitoring features: voltage, fan and temperature |
8 | * sensors, and manual and automatic fan speed control. | 8 | * sensors, and manual and automatic fan speed control. |
9 | * | 9 | * |
10 | * The F71872F/FG is almost the same, with two more voltages monitored, | ||
11 | * and 6 VID inputs. | ||
12 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 15 | * the Free Software Foundation; either version 2 of the License, or |
@@ -37,6 +40,7 @@ | |||
37 | static struct platform_device *pdev; | 40 | static struct platform_device *pdev; |
38 | 41 | ||
39 | #define DRVNAME "f71805f" | 42 | #define DRVNAME "f71805f" |
43 | enum kinds { f71805f, f71872f }; | ||
40 | 44 | ||
41 | /* | 45 | /* |
42 | * Super-I/O constants and functions | 46 | * Super-I/O constants and functions |
@@ -48,11 +52,13 @@ static struct platform_device *pdev; | |||
48 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | 52 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ |
49 | #define SIO_REG_DEVREV 0x22 /* Device revision */ | 53 | #define SIO_REG_DEVREV 0x22 /* Device revision */ |
50 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ | 54 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ |
55 | #define SIO_REG_FNSEL1 0x29 /* Multi Function Select 1 (F71872F) */ | ||
51 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ | 56 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ |
52 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | 57 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ |
53 | 58 | ||
54 | #define SIO_FINTEK_ID 0x1934 | 59 | #define SIO_FINTEK_ID 0x1934 |
55 | #define SIO_F71805F_ID 0x0406 | 60 | #define SIO_F71805F_ID 0x0406 |
61 | #define SIO_F71872F_ID 0x0341 | ||
56 | 62 | ||
57 | static inline int | 63 | static inline int |
58 | superio_inb(int base, int reg) | 64 | superio_inb(int base, int reg) |
@@ -96,22 +102,25 @@ superio_exit(int base) | |||
96 | * ISA constants | 102 | * ISA constants |
97 | */ | 103 | */ |
98 | 104 | ||
99 | #define REGION_LENGTH 2 | 105 | #define REGION_LENGTH 8 |
100 | #define ADDR_REG_OFFSET 0 | 106 | #define ADDR_REG_OFFSET 5 |
101 | #define DATA_REG_OFFSET 1 | 107 | #define DATA_REG_OFFSET 6 |
102 | 108 | ||
103 | /* | 109 | /* |
104 | * Registers | 110 | * Registers |
105 | */ | 111 | */ |
106 | 112 | ||
107 | /* in nr from 0 to 8 (8-bit values) */ | 113 | /* in nr from 0 to 10 (8-bit values) */ |
108 | #define F71805F_REG_IN(nr) (0x10 + (nr)) | 114 | #define F71805F_REG_IN(nr) (0x10 + (nr)) |
109 | #define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) | 115 | #define F71805F_REG_IN_HIGH(nr) ((nr) < 10 ? 0x40 + 2 * (nr) : 0x2E) |
110 | #define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) | 116 | #define F71805F_REG_IN_LOW(nr) ((nr) < 10 ? 0x41 + 2 * (nr) : 0x2F) |
111 | /* fan nr from 0 to 2 (12-bit values, two registers) */ | 117 | /* fan nr from 0 to 2 (12-bit values, two registers) */ |
112 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) | 118 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) |
113 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) | 119 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) |
120 | #define F71805F_REG_FAN_TARGET(nr) (0x69 + 16 * (nr)) | ||
114 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) | 121 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) |
122 | #define F71805F_REG_PWM_FREQ(nr) (0x63 + 16 * (nr)) | ||
123 | #define F71805F_REG_PWM_DUTY(nr) (0x6B + 16 * (nr)) | ||
115 | /* temp nr from 0 to 2 (8-bit values) */ | 124 | /* temp nr from 0 to 2 (8-bit values) */ |
116 | #define F71805F_REG_TEMP(nr) (0x1B + (nr)) | 125 | #define F71805F_REG_TEMP(nr) (0x1B + (nr)) |
117 | #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) | 126 | #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) |
@@ -122,6 +131,14 @@ superio_exit(int base) | |||
122 | /* status nr from 0 to 2 */ | 131 | /* status nr from 0 to 2 */ |
123 | #define F71805F_REG_STATUS(nr) (0x36 + (nr)) | 132 | #define F71805F_REG_STATUS(nr) (0x36 + (nr)) |
124 | 133 | ||
134 | /* individual register bits */ | ||
135 | #define FAN_CTRL_DC_MODE 0x10 | ||
136 | #define FAN_CTRL_LATCH_FULL 0x08 | ||
137 | #define FAN_CTRL_MODE_MASK 0x03 | ||
138 | #define FAN_CTRL_MODE_SPEED 0x00 | ||
139 | #define FAN_CTRL_MODE_TEMPERATURE 0x01 | ||
140 | #define FAN_CTRL_MODE_MANUAL 0x02 | ||
141 | |||
125 | /* | 142 | /* |
126 | * Data structures and manipulation thereof | 143 | * Data structures and manipulation thereof |
127 | */ | 144 | */ |
@@ -138,12 +155,16 @@ struct f71805f_data { | |||
138 | unsigned long last_limits; /* In jiffies */ | 155 | unsigned long last_limits; /* In jiffies */ |
139 | 156 | ||
140 | /* Register values */ | 157 | /* Register values */ |
141 | u8 in[9]; | 158 | u8 in[11]; |
142 | u8 in_high[9]; | 159 | u8 in_high[11]; |
143 | u8 in_low[9]; | 160 | u8 in_low[11]; |
161 | u16 has_in; | ||
144 | u16 fan[3]; | 162 | u16 fan[3]; |
145 | u16 fan_low[3]; | 163 | u16 fan_low[3]; |
146 | u8 fan_enabled; /* Read once at init time */ | 164 | u16 fan_target[3]; |
165 | u8 fan_ctrl[3]; | ||
166 | u8 pwm[3]; | ||
167 | u8 pwm_freq[3]; | ||
147 | u8 temp[3]; | 168 | u8 temp[3]; |
148 | u8 temp_high[3]; | 169 | u8 temp_high[3]; |
149 | u8 temp_hyst[3]; | 170 | u8 temp_hyst[3]; |
@@ -151,6 +172,11 @@ struct f71805f_data { | |||
151 | unsigned long alarms; | 172 | unsigned long alarms; |
152 | }; | 173 | }; |
153 | 174 | ||
175 | struct f71805f_sio_data { | ||
176 | enum kinds kind; | ||
177 | u8 fnsel1; | ||
178 | }; | ||
179 | |||
154 | static inline long in_from_reg(u8 reg) | 180 | static inline long in_from_reg(u8 reg) |
155 | { | 181 | { |
156 | return (reg * 8); | 182 | return (reg * 8); |
@@ -200,6 +226,33 @@ static inline u16 fan_to_reg(long rpm) | |||
200 | return (1500000 / rpm); | 226 | return (1500000 / rpm); |
201 | } | 227 | } |
202 | 228 | ||
229 | static inline unsigned long pwm_freq_from_reg(u8 reg) | ||
230 | { | ||
231 | unsigned long clock = (reg & 0x80) ? 48000000UL : 1000000UL; | ||
232 | |||
233 | reg &= 0x7f; | ||
234 | if (reg == 0) | ||
235 | reg++; | ||
236 | return clock / (reg << 8); | ||
237 | } | ||
238 | |||
239 | static inline u8 pwm_freq_to_reg(unsigned long val) | ||
240 | { | ||
241 | if (val >= 187500) /* The highest we can do */ | ||
242 | return 0x80; | ||
243 | if (val >= 1475) /* Use 48 MHz clock */ | ||
244 | return 0x80 | (48000000UL / (val << 8)); | ||
245 | if (val < 31) /* The lowest we can do */ | ||
246 | return 0x7f; | ||
247 | else /* Use 1 MHz clock */ | ||
248 | return 1000000UL / (val << 8); | ||
249 | } | ||
250 | |||
251 | static inline int pwm_mode_from_reg(u8 reg) | ||
252 | { | ||
253 | return !(reg & FAN_CTRL_DC_MODE); | ||
254 | } | ||
255 | |||
203 | static inline long temp_from_reg(u8 reg) | 256 | static inline long temp_from_reg(u8 reg) |
204 | { | 257 | { |
205 | return (reg * 1000); | 258 | return (reg * 1000); |
@@ -274,16 +327,21 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
274 | /* Limit registers cache is refreshed after 60 seconds */ | 327 | /* Limit registers cache is refreshed after 60 seconds */ |
275 | if (time_after(jiffies, data->last_updated + 60 * HZ) | 328 | if (time_after(jiffies, data->last_updated + 60 * HZ) |
276 | || !data->valid) { | 329 | || !data->valid) { |
277 | for (nr = 0; nr < 9; nr++) { | 330 | for (nr = 0; nr < 11; nr++) { |
331 | if (!(data->has_in & (1 << nr))) | ||
332 | continue; | ||
278 | data->in_high[nr] = f71805f_read8(data, | 333 | data->in_high[nr] = f71805f_read8(data, |
279 | F71805F_REG_IN_HIGH(nr)); | 334 | F71805F_REG_IN_HIGH(nr)); |
280 | data->in_low[nr] = f71805f_read8(data, | 335 | data->in_low[nr] = f71805f_read8(data, |
281 | F71805F_REG_IN_LOW(nr)); | 336 | F71805F_REG_IN_LOW(nr)); |
282 | } | 337 | } |
283 | for (nr = 0; nr < 3; nr++) { | 338 | for (nr = 0; nr < 3; nr++) { |
284 | if (data->fan_enabled & (1 << nr)) | 339 | data->fan_low[nr] = f71805f_read16(data, |
285 | data->fan_low[nr] = f71805f_read16(data, | 340 | F71805F_REG_FAN_LOW(nr)); |
286 | F71805F_REG_FAN_LOW(nr)); | 341 | data->fan_target[nr] = f71805f_read16(data, |
342 | F71805F_REG_FAN_TARGET(nr)); | ||
343 | data->pwm_freq[nr] = f71805f_read8(data, | ||
344 | F71805F_REG_PWM_FREQ(nr)); | ||
287 | } | 345 | } |
288 | for (nr = 0; nr < 3; nr++) { | 346 | for (nr = 0; nr < 3; nr++) { |
289 | data->temp_high[nr] = f71805f_read8(data, | 347 | data->temp_high[nr] = f71805f_read8(data, |
@@ -299,14 +357,19 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
299 | /* Measurement registers cache is refreshed after 1 second */ | 357 | /* Measurement registers cache is refreshed after 1 second */ |
300 | if (time_after(jiffies, data->last_updated + HZ) | 358 | if (time_after(jiffies, data->last_updated + HZ) |
301 | || !data->valid) { | 359 | || !data->valid) { |
302 | for (nr = 0; nr < 9; nr++) { | 360 | for (nr = 0; nr < 11; nr++) { |
361 | if (!(data->has_in & (1 << nr))) | ||
362 | continue; | ||
303 | data->in[nr] = f71805f_read8(data, | 363 | data->in[nr] = f71805f_read8(data, |
304 | F71805F_REG_IN(nr)); | 364 | F71805F_REG_IN(nr)); |
305 | } | 365 | } |
306 | for (nr = 0; nr < 3; nr++) { | 366 | for (nr = 0; nr < 3; nr++) { |
307 | if (data->fan_enabled & (1 << nr)) | 367 | data->fan[nr] = f71805f_read16(data, |
308 | data->fan[nr] = f71805f_read16(data, | 368 | F71805F_REG_FAN(nr)); |
309 | F71805F_REG_FAN(nr)); | 369 | data->fan_ctrl[nr] = f71805f_read8(data, |
370 | F71805F_REG_FAN_CTRL(nr)); | ||
371 | data->pwm[nr] = f71805f_read8(data, | ||
372 | F71805F_REG_PWM_DUTY(nr)); | ||
310 | } | 373 | } |
311 | for (nr = 0; nr < 3; nr++) { | 374 | for (nr = 0; nr < 3; nr++) { |
312 | data->temp[nr] = f71805f_read8(data, | 375 | data->temp[nr] = f71805f_read8(data, |
@@ -333,35 +396,43 @@ static ssize_t show_in0(struct device *dev, struct device_attribute *devattr, | |||
333 | char *buf) | 396 | char *buf) |
334 | { | 397 | { |
335 | struct f71805f_data *data = f71805f_update_device(dev); | 398 | struct f71805f_data *data = f71805f_update_device(dev); |
399 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
400 | int nr = attr->index; | ||
336 | 401 | ||
337 | return sprintf(buf, "%ld\n", in0_from_reg(data->in[0])); | 402 | return sprintf(buf, "%ld\n", in0_from_reg(data->in[nr])); |
338 | } | 403 | } |
339 | 404 | ||
340 | static ssize_t show_in0_max(struct device *dev, struct device_attribute | 405 | static ssize_t show_in0_max(struct device *dev, struct device_attribute |
341 | *devattr, char *buf) | 406 | *devattr, char *buf) |
342 | { | 407 | { |
343 | struct f71805f_data *data = f71805f_update_device(dev); | 408 | struct f71805f_data *data = f71805f_update_device(dev); |
409 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
410 | int nr = attr->index; | ||
344 | 411 | ||
345 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[0])); | 412 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[nr])); |
346 | } | 413 | } |
347 | 414 | ||
348 | static ssize_t show_in0_min(struct device *dev, struct device_attribute | 415 | static ssize_t show_in0_min(struct device *dev, struct device_attribute |
349 | *devattr, char *buf) | 416 | *devattr, char *buf) |
350 | { | 417 | { |
351 | struct f71805f_data *data = f71805f_update_device(dev); | 418 | struct f71805f_data *data = f71805f_update_device(dev); |
419 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
420 | int nr = attr->index; | ||
352 | 421 | ||
353 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[0])); | 422 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[nr])); |
354 | } | 423 | } |
355 | 424 | ||
356 | static ssize_t set_in0_max(struct device *dev, struct device_attribute | 425 | static ssize_t set_in0_max(struct device *dev, struct device_attribute |
357 | *devattr, const char *buf, size_t count) | 426 | *devattr, const char *buf, size_t count) |
358 | { | 427 | { |
359 | struct f71805f_data *data = dev_get_drvdata(dev); | 428 | struct f71805f_data *data = dev_get_drvdata(dev); |
429 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
430 | int nr = attr->index; | ||
360 | long val = simple_strtol(buf, NULL, 10); | 431 | long val = simple_strtol(buf, NULL, 10); |
361 | 432 | ||
362 | mutex_lock(&data->update_lock); | 433 | mutex_lock(&data->update_lock); |
363 | data->in_high[0] = in0_to_reg(val); | 434 | data->in_high[nr] = in0_to_reg(val); |
364 | f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]); | 435 | f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]); |
365 | mutex_unlock(&data->update_lock); | 436 | mutex_unlock(&data->update_lock); |
366 | 437 | ||
367 | return count; | 438 | return count; |
@@ -371,11 +442,13 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute | |||
371 | *devattr, const char *buf, size_t count) | 442 | *devattr, const char *buf, size_t count) |
372 | { | 443 | { |
373 | struct f71805f_data *data = dev_get_drvdata(dev); | 444 | struct f71805f_data *data = dev_get_drvdata(dev); |
445 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
446 | int nr = attr->index; | ||
374 | long val = simple_strtol(buf, NULL, 10); | 447 | long val = simple_strtol(buf, NULL, 10); |
375 | 448 | ||
376 | mutex_lock(&data->update_lock); | 449 | mutex_lock(&data->update_lock); |
377 | data->in_low[0] = in0_to_reg(val); | 450 | data->in_low[nr] = in0_to_reg(val); |
378 | f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]); | 451 | f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]); |
379 | mutex_unlock(&data->update_lock); | 452 | mutex_unlock(&data->update_lock); |
380 | 453 | ||
381 | return count; | 454 | return count; |
@@ -463,6 +536,16 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute | |||
463 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr])); | 536 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr])); |
464 | } | 537 | } |
465 | 538 | ||
539 | static ssize_t show_fan_target(struct device *dev, struct device_attribute | ||
540 | *devattr, char *buf) | ||
541 | { | ||
542 | struct f71805f_data *data = f71805f_update_device(dev); | ||
543 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
544 | int nr = attr->index; | ||
545 | |||
546 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_target[nr])); | ||
547 | } | ||
548 | |||
466 | static ssize_t set_fan_min(struct device *dev, struct device_attribute | 549 | static ssize_t set_fan_min(struct device *dev, struct device_attribute |
467 | *devattr, const char *buf, size_t count) | 550 | *devattr, const char *buf, size_t count) |
468 | { | 551 | { |
@@ -479,6 +562,157 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
479 | return count; | 562 | return count; |
480 | } | 563 | } |
481 | 564 | ||
565 | static ssize_t set_fan_target(struct device *dev, struct device_attribute | ||
566 | *devattr, const char *buf, size_t count) | ||
567 | { | ||
568 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
569 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
570 | int nr = attr->index; | ||
571 | long val = simple_strtol(buf, NULL, 10); | ||
572 | |||
573 | mutex_lock(&data->update_lock); | ||
574 | data->fan_target[nr] = fan_to_reg(val); | ||
575 | f71805f_write16(data, F71805F_REG_FAN_TARGET(nr), | ||
576 | data->fan_target[nr]); | ||
577 | mutex_unlock(&data->update_lock); | ||
578 | |||
579 | return count; | ||
580 | } | ||
581 | |||
582 | static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, | ||
583 | char *buf) | ||
584 | { | ||
585 | struct f71805f_data *data = f71805f_update_device(dev); | ||
586 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
587 | int nr = attr->index; | ||
588 | |||
589 | return sprintf(buf, "%d\n", (int)data->pwm[nr]); | ||
590 | } | ||
591 | |||
592 | static ssize_t show_pwm_enable(struct device *dev, struct device_attribute | ||
593 | *devattr, char *buf) | ||
594 | { | ||
595 | struct f71805f_data *data = f71805f_update_device(dev); | ||
596 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
597 | int nr = attr->index; | ||
598 | int mode; | ||
599 | |||
600 | switch (data->fan_ctrl[nr] & FAN_CTRL_MODE_MASK) { | ||
601 | case FAN_CTRL_MODE_SPEED: | ||
602 | mode = 3; | ||
603 | break; | ||
604 | case FAN_CTRL_MODE_TEMPERATURE: | ||
605 | mode = 2; | ||
606 | break; | ||
607 | default: /* MANUAL */ | ||
608 | mode = 1; | ||
609 | } | ||
610 | |||
611 | return sprintf(buf, "%d\n", mode); | ||
612 | } | ||
613 | |||
614 | static ssize_t show_pwm_freq(struct device *dev, struct device_attribute | ||
615 | *devattr, char *buf) | ||
616 | { | ||
617 | struct f71805f_data *data = f71805f_update_device(dev); | ||
618 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
619 | int nr = attr->index; | ||
620 | |||
621 | return sprintf(buf, "%lu\n", pwm_freq_from_reg(data->pwm_freq[nr])); | ||
622 | } | ||
623 | |||
624 | static ssize_t show_pwm_mode(struct device *dev, struct device_attribute | ||
625 | *devattr, char *buf) | ||
626 | { | ||
627 | struct f71805f_data *data = f71805f_update_device(dev); | ||
628 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
629 | int nr = attr->index; | ||
630 | |||
631 | return sprintf(buf, "%d\n", pwm_mode_from_reg(data->fan_ctrl[nr])); | ||
632 | } | ||
633 | |||
634 | static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, | ||
635 | const char *buf, size_t count) | ||
636 | { | ||
637 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
638 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
639 | int nr = attr->index; | ||
640 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
641 | |||
642 | if (val > 255) | ||
643 | return -EINVAL; | ||
644 | |||
645 | mutex_lock(&data->update_lock); | ||
646 | data->pwm[nr] = val; | ||
647 | f71805f_write8(data, F71805F_REG_PWM_DUTY(nr), data->pwm[nr]); | ||
648 | mutex_unlock(&data->update_lock); | ||
649 | |||
650 | return count; | ||
651 | } | ||
652 | |||
653 | static struct attribute *f71805f_attr_pwm[]; | ||
654 | |||
655 | static ssize_t set_pwm_enable(struct device *dev, struct device_attribute | ||
656 | *devattr, const char *buf, size_t count) | ||
657 | { | ||
658 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
659 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
660 | int nr = attr->index; | ||
661 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
662 | u8 reg; | ||
663 | |||
664 | if (val < 1 || val > 3) | ||
665 | return -EINVAL; | ||
666 | |||
667 | if (val > 1) { /* Automatic mode, user can't set PWM value */ | ||
668 | if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr], | ||
669 | S_IRUGO)) | ||
670 | dev_dbg(dev, "chmod -w pwm%d failed\n", nr + 1); | ||
671 | } | ||
672 | |||
673 | mutex_lock(&data->update_lock); | ||
674 | reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(nr)) | ||
675 | & ~FAN_CTRL_MODE_MASK; | ||
676 | switch (val) { | ||
677 | case 1: | ||
678 | reg |= FAN_CTRL_MODE_MANUAL; | ||
679 | break; | ||
680 | case 2: | ||
681 | reg |= FAN_CTRL_MODE_TEMPERATURE; | ||
682 | break; | ||
683 | case 3: | ||
684 | reg |= FAN_CTRL_MODE_SPEED; | ||
685 | break; | ||
686 | } | ||
687 | data->fan_ctrl[nr] = reg; | ||
688 | f71805f_write8(data, F71805F_REG_FAN_CTRL(nr), reg); | ||
689 | mutex_unlock(&data->update_lock); | ||
690 | |||
691 | if (val == 1) { /* Manual mode, user can set PWM value */ | ||
692 | if (sysfs_chmod_file(&dev->kobj, f71805f_attr_pwm[nr], | ||
693 | S_IRUGO | S_IWUSR)) | ||
694 | dev_dbg(dev, "chmod +w pwm%d failed\n", nr + 1); | ||
695 | } | ||
696 | |||
697 | return count; | ||
698 | } | ||
699 | |||
700 | static ssize_t set_pwm_freq(struct device *dev, struct device_attribute | ||
701 | *devattr, const char *buf, size_t count) | ||
702 | { | ||
703 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
704 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
705 | int nr = attr->index; | ||
706 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
707 | |||
708 | mutex_lock(&data->update_lock); | ||
709 | data->pwm_freq[nr] = pwm_freq_to_reg(val); | ||
710 | f71805f_write8(data, F71805F_REG_PWM_FREQ(nr), data->pwm_freq[nr]); | ||
711 | mutex_unlock(&data->update_lock); | ||
712 | |||
713 | return count; | ||
714 | } | ||
715 | |||
482 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | 716 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
483 | char *buf) | 717 | char *buf) |
484 | { | 718 | { |
@@ -557,7 +791,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute | |||
557 | { | 791 | { |
558 | struct f71805f_data *data = f71805f_update_device(dev); | 792 | struct f71805f_data *data = f71805f_update_device(dev); |
559 | 793 | ||
560 | return sprintf(buf, "%lu\n", data->alarms & 0x1ff); | 794 | return sprintf(buf, "%lu\n", data->alarms & 0x7ff); |
561 | } | 795 | } |
562 | 796 | ||
563 | static ssize_t show_alarms_fan(struct device *dev, struct device_attribute | 797 | static ssize_t show_alarms_fan(struct device *dev, struct device_attribute |
@@ -594,9 +828,11 @@ static ssize_t show_name(struct device *dev, struct device_attribute | |||
594 | return sprintf(buf, "%s\n", data->name); | 828 | return sprintf(buf, "%s\n", data->name); |
595 | } | 829 | } |
596 | 830 | ||
597 | static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); | 831 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL, 0); |
598 | static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); | 832 | static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, |
599 | static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); | 833 | show_in0_max, set_in0_max, 0); |
834 | static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, | ||
835 | show_in0_min, set_in0_min, 0); | ||
600 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); | 836 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); |
601 | static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, | 837 | static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, |
602 | show_in_max, set_in_max, 1); | 838 | show_in_max, set_in_max, 1); |
@@ -637,16 +873,32 @@ static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR, | |||
637 | show_in_max, set_in_max, 8); | 873 | show_in_max, set_in_max, 8); |
638 | static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, | 874 | static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, |
639 | show_in_min, set_in_min, 8); | 875 | show_in_min, set_in_min, 8); |
876 | static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in0, NULL, 9); | ||
877 | static SENSOR_DEVICE_ATTR(in9_max, S_IRUGO | S_IWUSR, | ||
878 | show_in0_max, set_in0_max, 9); | ||
879 | static SENSOR_DEVICE_ATTR(in9_min, S_IRUGO | S_IWUSR, | ||
880 | show_in0_min, set_in0_min, 9); | ||
881 | static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in0, NULL, 10); | ||
882 | static SENSOR_DEVICE_ATTR(in10_max, S_IRUGO | S_IWUSR, | ||
883 | show_in0_max, set_in0_max, 10); | ||
884 | static SENSOR_DEVICE_ATTR(in10_min, S_IRUGO | S_IWUSR, | ||
885 | show_in0_min, set_in0_min, 10); | ||
640 | 886 | ||
641 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | 887 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); |
642 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, | 888 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, |
643 | show_fan_min, set_fan_min, 0); | 889 | show_fan_min, set_fan_min, 0); |
890 | static SENSOR_DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, | ||
891 | show_fan_target, set_fan_target, 0); | ||
644 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); | 892 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); |
645 | static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, | 893 | static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, |
646 | show_fan_min, set_fan_min, 1); | 894 | show_fan_min, set_fan_min, 1); |
895 | static SENSOR_DEVICE_ATTR(fan2_target, S_IRUGO | S_IWUSR, | ||
896 | show_fan_target, set_fan_target, 1); | ||
647 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); | 897 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); |
648 | static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, | 898 | static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, |
649 | show_fan_min, set_fan_min, 2); | 899 | show_fan_min, set_fan_min, 2); |
900 | static SENSOR_DEVICE_ATTR(fan3_target, S_IRUGO | S_IWUSR, | ||
901 | show_fan_target, set_fan_target, 2); | ||
650 | 902 | ||
651 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); | 903 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); |
652 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, | 904 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, |
@@ -667,6 +919,27 @@ static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, | |||
667 | show_temp_hyst, set_temp_hyst, 2); | 919 | show_temp_hyst, set_temp_hyst, 2); |
668 | static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); | 920 | static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); |
669 | 921 | ||
922 | /* pwm (value) files are created read-only, write permission is | ||
923 | then added or removed dynamically as needed */ | ||
924 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0); | ||
925 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, | ||
926 | show_pwm_enable, set_pwm_enable, 0); | ||
927 | static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, | ||
928 | show_pwm_freq, set_pwm_freq, 0); | ||
929 | static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); | ||
930 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO, show_pwm, set_pwm, 1); | ||
931 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, | ||
932 | show_pwm_enable, set_pwm_enable, 1); | ||
933 | static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO | S_IWUSR, | ||
934 | show_pwm_freq, set_pwm_freq, 1); | ||
935 | static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); | ||
936 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO, show_pwm, set_pwm, 2); | ||
937 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, | ||
938 | show_pwm_enable, set_pwm_enable, 2); | ||
939 | static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR, | ||
940 | show_pwm_freq, set_pwm_freq, 2); | ||
941 | static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); | ||
942 | |||
670 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); | 943 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); |
671 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); | 944 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); |
672 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); | 945 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); |
@@ -676,6 +949,8 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); | |||
676 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); | 949 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); |
677 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); | 950 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); |
678 | static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); | 951 | static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); |
952 | static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9); | ||
953 | static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10); | ||
679 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); | 954 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); |
680 | static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); | 955 | static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); |
681 | static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); | 956 | static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); |
@@ -689,9 +964,9 @@ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); | |||
689 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 964 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
690 | 965 | ||
691 | static struct attribute *f71805f_attributes[] = { | 966 | static struct attribute *f71805f_attributes[] = { |
692 | &dev_attr_in0_input.attr, | 967 | &sensor_dev_attr_in0_input.dev_attr.attr, |
693 | &dev_attr_in0_max.attr, | 968 | &sensor_dev_attr_in0_max.dev_attr.attr, |
694 | &dev_attr_in0_min.attr, | 969 | &sensor_dev_attr_in0_min.dev_attr.attr, |
695 | &sensor_dev_attr_in1_input.dev_attr.attr, | 970 | &sensor_dev_attr_in1_input.dev_attr.attr, |
696 | &sensor_dev_attr_in1_max.dev_attr.attr, | 971 | &sensor_dev_attr_in1_max.dev_attr.attr, |
697 | &sensor_dev_attr_in1_min.dev_attr.attr, | 972 | &sensor_dev_attr_in1_min.dev_attr.attr, |
@@ -701,9 +976,6 @@ static struct attribute *f71805f_attributes[] = { | |||
701 | &sensor_dev_attr_in3_input.dev_attr.attr, | 976 | &sensor_dev_attr_in3_input.dev_attr.attr, |
702 | &sensor_dev_attr_in3_max.dev_attr.attr, | 977 | &sensor_dev_attr_in3_max.dev_attr.attr, |
703 | &sensor_dev_attr_in3_min.dev_attr.attr, | 978 | &sensor_dev_attr_in3_min.dev_attr.attr, |
704 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
705 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
706 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
707 | &sensor_dev_attr_in5_input.dev_attr.attr, | 979 | &sensor_dev_attr_in5_input.dev_attr.attr, |
708 | &sensor_dev_attr_in5_max.dev_attr.attr, | 980 | &sensor_dev_attr_in5_max.dev_attr.attr, |
709 | &sensor_dev_attr_in5_min.dev_attr.attr, | 981 | &sensor_dev_attr_in5_min.dev_attr.attr, |
@@ -713,9 +985,29 @@ static struct attribute *f71805f_attributes[] = { | |||
713 | &sensor_dev_attr_in7_input.dev_attr.attr, | 985 | &sensor_dev_attr_in7_input.dev_attr.attr, |
714 | &sensor_dev_attr_in7_max.dev_attr.attr, | 986 | &sensor_dev_attr_in7_max.dev_attr.attr, |
715 | &sensor_dev_attr_in7_min.dev_attr.attr, | 987 | &sensor_dev_attr_in7_min.dev_attr.attr, |
716 | &sensor_dev_attr_in8_input.dev_attr.attr, | 988 | |
717 | &sensor_dev_attr_in8_max.dev_attr.attr, | 989 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
718 | &sensor_dev_attr_in8_min.dev_attr.attr, | 990 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
991 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | ||
992 | &sensor_dev_attr_fan1_target.dev_attr.attr, | ||
993 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
994 | &sensor_dev_attr_fan2_min.dev_attr.attr, | ||
995 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | ||
996 | &sensor_dev_attr_fan2_target.dev_attr.attr, | ||
997 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
998 | &sensor_dev_attr_fan3_min.dev_attr.attr, | ||
999 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | ||
1000 | &sensor_dev_attr_fan3_target.dev_attr.attr, | ||
1001 | |||
1002 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
1003 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
1004 | &sensor_dev_attr_pwm1_mode.dev_attr.attr, | ||
1005 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
1006 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
1007 | &sensor_dev_attr_pwm2_mode.dev_attr.attr, | ||
1008 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
1009 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
1010 | &sensor_dev_attr_pwm3_mode.dev_attr.attr, | ||
719 | 1011 | ||
720 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 1012 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
721 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 1013 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
@@ -734,11 +1026,9 @@ static struct attribute *f71805f_attributes[] = { | |||
734 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | 1026 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
735 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | 1027 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |
736 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | 1028 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
737 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | ||
738 | &sensor_dev_attr_in5_alarm.dev_attr.attr, | 1029 | &sensor_dev_attr_in5_alarm.dev_attr.attr, |
739 | &sensor_dev_attr_in6_alarm.dev_attr.attr, | 1030 | &sensor_dev_attr_in6_alarm.dev_attr.attr, |
740 | &sensor_dev_attr_in7_alarm.dev_attr.attr, | 1031 | &sensor_dev_attr_in7_alarm.dev_attr.attr, |
741 | &sensor_dev_attr_in8_alarm.dev_attr.attr, | ||
742 | &dev_attr_alarms_in.attr, | 1032 | &dev_attr_alarms_in.attr, |
743 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | 1033 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, |
744 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | 1034 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, |
@@ -754,29 +1044,59 @@ static const struct attribute_group f71805f_group = { | |||
754 | .attrs = f71805f_attributes, | 1044 | .attrs = f71805f_attributes, |
755 | }; | 1045 | }; |
756 | 1046 | ||
757 | static struct attribute *f71805f_attributes_fan[3][4] = { | 1047 | static struct attribute *f71805f_attributes_optin[4][5] = { |
758 | { | 1048 | { |
759 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 1049 | &sensor_dev_attr_in4_input.dev_attr.attr, |
760 | &sensor_dev_attr_fan1_min.dev_attr.attr, | 1050 | &sensor_dev_attr_in4_max.dev_attr.attr, |
761 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | 1051 | &sensor_dev_attr_in4_min.dev_attr.attr, |
1052 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | ||
1053 | NULL | ||
1054 | }, { | ||
1055 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1056 | &sensor_dev_attr_in8_max.dev_attr.attr, | ||
1057 | &sensor_dev_attr_in8_min.dev_attr.attr, | ||
1058 | &sensor_dev_attr_in8_alarm.dev_attr.attr, | ||
762 | NULL | 1059 | NULL |
763 | }, { | 1060 | }, { |
764 | &sensor_dev_attr_fan2_input.dev_attr.attr, | 1061 | &sensor_dev_attr_in9_input.dev_attr.attr, |
765 | &sensor_dev_attr_fan2_min.dev_attr.attr, | 1062 | &sensor_dev_attr_in9_max.dev_attr.attr, |
766 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | 1063 | &sensor_dev_attr_in9_min.dev_attr.attr, |
1064 | &sensor_dev_attr_in9_alarm.dev_attr.attr, | ||
767 | NULL | 1065 | NULL |
768 | }, { | 1066 | }, { |
769 | &sensor_dev_attr_fan3_input.dev_attr.attr, | 1067 | &sensor_dev_attr_in10_input.dev_attr.attr, |
770 | &sensor_dev_attr_fan3_min.dev_attr.attr, | 1068 | &sensor_dev_attr_in10_max.dev_attr.attr, |
771 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | 1069 | &sensor_dev_attr_in10_min.dev_attr.attr, |
1070 | &sensor_dev_attr_in10_alarm.dev_attr.attr, | ||
772 | NULL | 1071 | NULL |
773 | } | 1072 | } |
774 | }; | 1073 | }; |
775 | 1074 | ||
776 | static const struct attribute_group f71805f_group_fan[3] = { | 1075 | static const struct attribute_group f71805f_group_optin[4] = { |
777 | { .attrs = f71805f_attributes_fan[0] }, | 1076 | { .attrs = f71805f_attributes_optin[0] }, |
778 | { .attrs = f71805f_attributes_fan[1] }, | 1077 | { .attrs = f71805f_attributes_optin[1] }, |
779 | { .attrs = f71805f_attributes_fan[2] }, | 1078 | { .attrs = f71805f_attributes_optin[2] }, |
1079 | { .attrs = f71805f_attributes_optin[3] }, | ||
1080 | }; | ||
1081 | |||
1082 | /* We don't include pwm_freq files in the arrays above, because they must be | ||
1083 | created conditionally (only if pwm_mode is 1 == PWM) */ | ||
1084 | static struct attribute *f71805f_attributes_pwm_freq[] = { | ||
1085 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | ||
1086 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | ||
1087 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | ||
1088 | NULL | ||
1089 | }; | ||
1090 | |||
1091 | static const struct attribute_group f71805f_group_pwm_freq = { | ||
1092 | .attrs = f71805f_attributes_pwm_freq, | ||
1093 | }; | ||
1094 | |||
1095 | /* We also need an indexed access to pwmN files to toggle writability */ | ||
1096 | static struct attribute *f71805f_attr_pwm[] = { | ||
1097 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
1098 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
1099 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
780 | }; | 1100 | }; |
781 | 1101 | ||
782 | /* | 1102 | /* |
@@ -798,18 +1118,30 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) | |||
798 | /* Fan monitoring can be disabled. If it is, we won't be polling | 1118 | /* Fan monitoring can be disabled. If it is, we won't be polling |
799 | the register values, and won't create the related sysfs files. */ | 1119 | the register values, and won't create the related sysfs files. */ |
800 | for (i = 0; i < 3; i++) { | 1120 | for (i = 0; i < 3; i++) { |
801 | reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(i)); | 1121 | data->fan_ctrl[i] = f71805f_read8(data, |
802 | if (!(reg & 0x80)) | 1122 | F71805F_REG_FAN_CTRL(i)); |
803 | data->fan_enabled |= (1 << i); | 1123 | /* Clear latch full bit, else "speed mode" fan speed control |
1124 | doesn't work */ | ||
1125 | if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) { | ||
1126 | data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL; | ||
1127 | f71805f_write8(data, F71805F_REG_FAN_CTRL(i), | ||
1128 | data->fan_ctrl[i]); | ||
1129 | } | ||
804 | } | 1130 | } |
805 | } | 1131 | } |
806 | 1132 | ||
807 | static int __devinit f71805f_probe(struct platform_device *pdev) | 1133 | static int __devinit f71805f_probe(struct platform_device *pdev) |
808 | { | 1134 | { |
1135 | struct f71805f_sio_data *sio_data = pdev->dev.platform_data; | ||
809 | struct f71805f_data *data; | 1136 | struct f71805f_data *data; |
810 | struct resource *res; | 1137 | struct resource *res; |
811 | int i, err; | 1138 | int i, err; |
812 | 1139 | ||
1140 | static const char *names[] = { | ||
1141 | "f71805f", | ||
1142 | "f71872f", | ||
1143 | }; | ||
1144 | |||
813 | if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { | 1145 | if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { |
814 | err = -ENOMEM; | 1146 | err = -ENOMEM; |
815 | printk(KERN_ERR DRVNAME ": Out of memory\n"); | 1147 | printk(KERN_ERR DRVNAME ": Out of memory\n"); |
@@ -819,24 +1151,69 @@ static int __devinit f71805f_probe(struct platform_device *pdev) | |||
819 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1151 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
820 | data->addr = res->start; | 1152 | data->addr = res->start; |
821 | mutex_init(&data->lock); | 1153 | mutex_init(&data->lock); |
822 | data->name = "f71805f"; | 1154 | data->name = names[sio_data->kind]; |
823 | mutex_init(&data->update_lock); | 1155 | mutex_init(&data->update_lock); |
824 | 1156 | ||
825 | platform_set_drvdata(pdev, data); | 1157 | platform_set_drvdata(pdev, data); |
826 | 1158 | ||
1159 | /* Some voltage inputs depend on chip model and configuration */ | ||
1160 | switch (sio_data->kind) { | ||
1161 | case f71805f: | ||
1162 | data->has_in = 0x1ff; | ||
1163 | break; | ||
1164 | case f71872f: | ||
1165 | data->has_in = 0x6ef; | ||
1166 | if (sio_data->fnsel1 & 0x01) | ||
1167 | data->has_in |= (1 << 4); /* in4 */ | ||
1168 | if (sio_data->fnsel1 & 0x02) | ||
1169 | data->has_in |= (1 << 8); /* in8 */ | ||
1170 | break; | ||
1171 | } | ||
1172 | |||
827 | /* Initialize the F71805F chip */ | 1173 | /* Initialize the F71805F chip */ |
828 | f71805f_init_device(data); | 1174 | f71805f_init_device(data); |
829 | 1175 | ||
830 | /* Register sysfs interface files */ | 1176 | /* Register sysfs interface files */ |
831 | if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) | 1177 | if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) |
832 | goto exit_free; | 1178 | goto exit_free; |
833 | for (i = 0; i < 3; i++) { | 1179 | if (data->has_in & (1 << 4)) { /* in4 */ |
834 | if (!(data->fan_enabled & (1 << i))) | 1180 | if ((err = sysfs_create_group(&pdev->dev.kobj, |
835 | continue; | 1181 | &f71805f_group_optin[0]))) |
1182 | goto exit_remove_files; | ||
1183 | } | ||
1184 | if (data->has_in & (1 << 8)) { /* in8 */ | ||
1185 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1186 | &f71805f_group_optin[1]))) | ||
1187 | goto exit_remove_files; | ||
1188 | } | ||
1189 | if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */ | ||
836 | if ((err = sysfs_create_group(&pdev->dev.kobj, | 1190 | if ((err = sysfs_create_group(&pdev->dev.kobj, |
837 | &f71805f_group_fan[i]))) | 1191 | &f71805f_group_optin[2]))) |
838 | goto exit_remove_files; | 1192 | goto exit_remove_files; |
839 | } | 1193 | } |
1194 | if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */ | ||
1195 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1196 | &f71805f_group_optin[3]))) | ||
1197 | goto exit_remove_files; | ||
1198 | } | ||
1199 | for (i = 0; i < 3; i++) { | ||
1200 | /* If control mode is PWM, create pwm_freq file */ | ||
1201 | if (!(data->fan_ctrl[i] & FAN_CTRL_DC_MODE)) { | ||
1202 | if ((err = sysfs_create_file(&pdev->dev.kobj, | ||
1203 | f71805f_attributes_pwm_freq[i]))) | ||
1204 | goto exit_remove_files; | ||
1205 | } | ||
1206 | /* If PWM is in manual mode, add write permission */ | ||
1207 | if (data->fan_ctrl[i] & FAN_CTRL_MODE_MANUAL) { | ||
1208 | if ((err = sysfs_chmod_file(&pdev->dev.kobj, | ||
1209 | f71805f_attr_pwm[i], | ||
1210 | S_IRUGO | S_IWUSR))) { | ||
1211 | dev_err(&pdev->dev, "chmod +w pwm%d failed\n", | ||
1212 | i + 1); | ||
1213 | goto exit_remove_files; | ||
1214 | } | ||
1215 | } | ||
1216 | } | ||
840 | 1217 | ||
841 | data->class_dev = hwmon_device_register(&pdev->dev); | 1218 | data->class_dev = hwmon_device_register(&pdev->dev); |
842 | if (IS_ERR(data->class_dev)) { | 1219 | if (IS_ERR(data->class_dev)) { |
@@ -849,8 +1226,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev) | |||
849 | 1226 | ||
850 | exit_remove_files: | 1227 | exit_remove_files: |
851 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); | 1228 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); |
852 | for (i = 0; i < 3; i++) | 1229 | for (i = 0; i < 4; i++) |
853 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); | 1230 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); |
1231 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); | ||
854 | exit_free: | 1232 | exit_free: |
855 | platform_set_drvdata(pdev, NULL); | 1233 | platform_set_drvdata(pdev, NULL); |
856 | kfree(data); | 1234 | kfree(data); |
@@ -866,8 +1244,9 @@ static int __devexit f71805f_remove(struct platform_device *pdev) | |||
866 | platform_set_drvdata(pdev, NULL); | 1244 | platform_set_drvdata(pdev, NULL); |
867 | hwmon_device_unregister(data->class_dev); | 1245 | hwmon_device_unregister(data->class_dev); |
868 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); | 1246 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); |
869 | for (i = 0; i < 3; i++) | 1247 | for (i = 0; i < 4; i++) |
870 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); | 1248 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); |
1249 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); | ||
871 | kfree(data); | 1250 | kfree(data); |
872 | 1251 | ||
873 | return 0; | 1252 | return 0; |
@@ -882,7 +1261,8 @@ static struct platform_driver f71805f_driver = { | |||
882 | .remove = __devexit_p(f71805f_remove), | 1261 | .remove = __devexit_p(f71805f_remove), |
883 | }; | 1262 | }; |
884 | 1263 | ||
885 | static int __init f71805f_device_add(unsigned short address) | 1264 | static int __init f71805f_device_add(unsigned short address, |
1265 | const struct f71805f_sio_data *sio_data) | ||
886 | { | 1266 | { |
887 | struct resource res = { | 1267 | struct resource res = { |
888 | .start = address, | 1268 | .start = address, |
@@ -906,26 +1286,45 @@ static int __init f71805f_device_add(unsigned short address) | |||
906 | goto exit_device_put; | 1286 | goto exit_device_put; |
907 | } | 1287 | } |
908 | 1288 | ||
1289 | pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data), | ||
1290 | GFP_KERNEL); | ||
1291 | if (!pdev->dev.platform_data) { | ||
1292 | err = -ENOMEM; | ||
1293 | printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); | ||
1294 | goto exit_device_put; | ||
1295 | } | ||
1296 | memcpy(pdev->dev.platform_data, sio_data, | ||
1297 | sizeof(struct f71805f_sio_data)); | ||
1298 | |||
909 | err = platform_device_add(pdev); | 1299 | err = platform_device_add(pdev); |
910 | if (err) { | 1300 | if (err) { |
911 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", | 1301 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", |
912 | err); | 1302 | err); |
913 | goto exit_device_put; | 1303 | goto exit_kfree_data; |
914 | } | 1304 | } |
915 | 1305 | ||
916 | return 0; | 1306 | return 0; |
917 | 1307 | ||
1308 | exit_kfree_data: | ||
1309 | kfree(pdev->dev.platform_data); | ||
1310 | pdev->dev.platform_data = NULL; | ||
918 | exit_device_put: | 1311 | exit_device_put: |
919 | platform_device_put(pdev); | 1312 | platform_device_put(pdev); |
920 | exit: | 1313 | exit: |
921 | return err; | 1314 | return err; |
922 | } | 1315 | } |
923 | 1316 | ||
924 | static int __init f71805f_find(int sioaddr, unsigned short *address) | 1317 | static int __init f71805f_find(int sioaddr, unsigned short *address, |
1318 | struct f71805f_sio_data *sio_data) | ||
925 | { | 1319 | { |
926 | int err = -ENODEV; | 1320 | int err = -ENODEV; |
927 | u16 devid; | 1321 | u16 devid; |
928 | 1322 | ||
1323 | static const char *names[] = { | ||
1324 | "F71805F/FG", | ||
1325 | "F71872F/FG", | ||
1326 | }; | ||
1327 | |||
929 | superio_enter(sioaddr); | 1328 | superio_enter(sioaddr); |
930 | 1329 | ||
931 | devid = superio_inw(sioaddr, SIO_REG_MANID); | 1330 | devid = superio_inw(sioaddr, SIO_REG_MANID); |
@@ -933,7 +1332,15 @@ static int __init f71805f_find(int sioaddr, unsigned short *address) | |||
933 | goto exit; | 1332 | goto exit; |
934 | 1333 | ||
935 | devid = superio_inw(sioaddr, SIO_REG_DEVID); | 1334 | devid = superio_inw(sioaddr, SIO_REG_DEVID); |
936 | if (devid != SIO_F71805F_ID) { | 1335 | switch (devid) { |
1336 | case SIO_F71805F_ID: | ||
1337 | sio_data->kind = f71805f; | ||
1338 | break; | ||
1339 | case SIO_F71872F_ID: | ||
1340 | sio_data->kind = f71872f; | ||
1341 | sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1); | ||
1342 | break; | ||
1343 | default: | ||
937 | printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " | 1344 | printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " |
938 | "skipping\n"); | 1345 | "skipping\n"); |
939 | goto exit; | 1346 | goto exit; |
@@ -952,10 +1359,12 @@ static int __init f71805f_find(int sioaddr, unsigned short *address) | |||
952 | "skipping\n"); | 1359 | "skipping\n"); |
953 | goto exit; | 1360 | goto exit; |
954 | } | 1361 | } |
1362 | *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ | ||
955 | 1363 | ||
956 | err = 0; | 1364 | err = 0; |
957 | printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", | 1365 | printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n", |
958 | *address, superio_inb(sioaddr, SIO_REG_DEVREV)); | 1366 | names[sio_data->kind], *address, |
1367 | superio_inb(sioaddr, SIO_REG_DEVREV)); | ||
959 | 1368 | ||
960 | exit: | 1369 | exit: |
961 | superio_exit(sioaddr); | 1370 | superio_exit(sioaddr); |
@@ -966,9 +1375,10 @@ static int __init f71805f_init(void) | |||
966 | { | 1375 | { |
967 | int err; | 1376 | int err; |
968 | unsigned short address; | 1377 | unsigned short address; |
1378 | struct f71805f_sio_data sio_data; | ||
969 | 1379 | ||
970 | if (f71805f_find(0x2e, &address) | 1380 | if (f71805f_find(0x2e, &address, &sio_data) |
971 | && f71805f_find(0x4e, &address)) | 1381 | && f71805f_find(0x4e, &address, &sio_data)) |
972 | return -ENODEV; | 1382 | return -ENODEV; |
973 | 1383 | ||
974 | err = platform_driver_register(&f71805f_driver); | 1384 | err = platform_driver_register(&f71805f_driver); |
@@ -976,7 +1386,7 @@ static int __init f71805f_init(void) | |||
976 | goto exit; | 1386 | goto exit; |
977 | 1387 | ||
978 | /* Sets global pdev as a side effect */ | 1388 | /* Sets global pdev as a side effect */ |
979 | err = f71805f_device_add(address); | 1389 | err = f71805f_device_add(address, &sio_data); |
980 | if (err) | 1390 | if (err) |
981 | goto exit_driver; | 1391 | goto exit_driver; |
982 | 1392 | ||
@@ -990,13 +1400,16 @@ exit: | |||
990 | 1400 | ||
991 | static void __exit f71805f_exit(void) | 1401 | static void __exit f71805f_exit(void) |
992 | { | 1402 | { |
1403 | kfree(pdev->dev.platform_data); | ||
1404 | pdev->dev.platform_data = NULL; | ||
993 | platform_device_unregister(pdev); | 1405 | platform_device_unregister(pdev); |
1406 | |||
994 | platform_driver_unregister(&f71805f_driver); | 1407 | platform_driver_unregister(&f71805f_driver); |
995 | } | 1408 | } |
996 | 1409 | ||
997 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); | 1410 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); |
998 | MODULE_LICENSE("GPL"); | 1411 | MODULE_LICENSE("GPL"); |
999 | MODULE_DESCRIPTION("F71805F hardware monitoring driver"); | 1412 | MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver"); |
1000 | 1413 | ||
1001 | module_init(f71805f_init); | 1414 | module_init(f71805f_init); |
1002 | module_exit(f71805f_exit); | 1415 | module_exit(f71805f_exit); |