diff options
Diffstat (limited to 'drivers/hwmon/pc87427.c')
-rw-r--r-- | drivers/hwmon/pc87427.c | 862 |
1 files changed, 789 insertions, 73 deletions
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 3170b26d2443..9ec4daaf6ca6 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * pc87427.c - hardware monitoring driver for the | 2 | * pc87427.c - hardware monitoring driver for the |
3 | * National Semiconductor PC87427 Super-I/O chip | 3 | * National Semiconductor PC87427 Super-I/O chip |
4 | * Copyright (C) 2006 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2006, 2008, 2010 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
@@ -15,10 +15,11 @@ | |||
15 | * Supports the following chips: | 15 | * Supports the following chips: |
16 | * | 16 | * |
17 | * Chip #vin #fan #pwm #temp devid | 17 | * Chip #vin #fan #pwm #temp devid |
18 | * PC87427 - 8 - - 0xF2 | 18 | * PC87427 - 8 4 6 0xF2 |
19 | * | 19 | * |
20 | * This driver assumes that no more than one chip is present. | 20 | * This driver assumes that no more than one chip is present. |
21 | * Only fan inputs are supported so far, although the chip can do much more. | 21 | * Only fans are fully supported so far. Temperatures are in read-only |
22 | * mode, and voltages aren't supported at all. | ||
22 | */ | 23 | */ |
23 | 24 | ||
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -57,6 +58,25 @@ struct pc87427_data { | |||
57 | u16 fan[8]; /* register values */ | 58 | u16 fan[8]; /* register values */ |
58 | u16 fan_min[8]; /* register values */ | 59 | u16 fan_min[8]; /* register values */ |
59 | u8 fan_status[8]; /* register values */ | 60 | u8 fan_status[8]; /* register values */ |
61 | |||
62 | u8 pwm_enabled; /* bit vector */ | ||
63 | u8 pwm_auto_ok; /* bit vector */ | ||
64 | u8 pwm_enable[4]; /* register values */ | ||
65 | u8 pwm[4]; /* register values */ | ||
66 | |||
67 | u8 temp_enabled; /* bit vector */ | ||
68 | s16 temp[6]; /* register values */ | ||
69 | s8 temp_min[6]; /* register values */ | ||
70 | s8 temp_max[6]; /* register values */ | ||
71 | s8 temp_crit[6]; /* register values */ | ||
72 | u8 temp_status[6]; /* register values */ | ||
73 | u8 temp_type[6]; /* register values */ | ||
74 | }; | ||
75 | |||
76 | struct pc87427_sio_data { | ||
77 | unsigned short address[2]; | ||
78 | u8 has_fanin; | ||
79 | u8 has_fanout; | ||
60 | }; | 80 | }; |
61 | 81 | ||
62 | /* | 82 | /* |
@@ -65,6 +85,13 @@ struct pc87427_data { | |||
65 | 85 | ||
66 | #define SIOREG_LDSEL 0x07 /* Logical device select */ | 86 | #define SIOREG_LDSEL 0x07 /* Logical device select */ |
67 | #define SIOREG_DEVID 0x20 /* Device ID */ | 87 | #define SIOREG_DEVID 0x20 /* Device ID */ |
88 | #define SIOREG_CF2 0x22 /* Configuration 2 */ | ||
89 | #define SIOREG_CF3 0x23 /* Configuration 3 */ | ||
90 | #define SIOREG_CF4 0x24 /* Configuration 4 */ | ||
91 | #define SIOREG_CF5 0x25 /* Configuration 5 */ | ||
92 | #define SIOREG_CFB 0x2B /* Configuration B */ | ||
93 | #define SIOREG_CFC 0x2C /* Configuration C */ | ||
94 | #define SIOREG_CFD 0x2D /* Configuration D */ | ||
68 | #define SIOREG_ACT 0x30 /* Device activation */ | 95 | #define SIOREG_ACT 0x30 /* Device activation */ |
69 | #define SIOREG_MAP 0x50 /* I/O or memory mapping */ | 96 | #define SIOREG_MAP 0x50 /* I/O or memory mapping */ |
70 | #define SIOREG_IOBASE 0x60 /* I/O base address */ | 97 | #define SIOREG_IOBASE 0x60 /* I/O base address */ |
@@ -102,6 +129,8 @@ static inline void superio_exit(int sioaddr) | |||
102 | #define BANK_FM(nr) (nr) | 129 | #define BANK_FM(nr) (nr) |
103 | #define BANK_FT(nr) (0x08 + (nr)) | 130 | #define BANK_FT(nr) (0x08 + (nr)) |
104 | #define BANK_FC(nr) (0x10 + (nr) * 2) | 131 | #define BANK_FC(nr) (0x10 + (nr) * 2) |
132 | #define BANK_TM(nr) (nr) | ||
133 | #define BANK_VM(nr) (0x08 + (nr)) | ||
105 | 134 | ||
106 | /* | 135 | /* |
107 | * I/O access functions | 136 | * I/O access functions |
@@ -179,6 +208,127 @@ static inline u16 fan_to_reg(unsigned long val) | |||
179 | } | 208 | } |
180 | 209 | ||
181 | /* | 210 | /* |
211 | * PWM registers and conversions | ||
212 | */ | ||
213 | |||
214 | #define PC87427_REG_PWM_ENABLE 0x10 | ||
215 | #define PC87427_REG_PWM_DUTY 0x12 | ||
216 | |||
217 | #define PWM_ENABLE_MODE_MASK (7 << 4) | ||
218 | #define PWM_ENABLE_CTLEN (1 << 0) | ||
219 | |||
220 | #define PWM_MODE_MANUAL (0 << 4) | ||
221 | #define PWM_MODE_AUTO (1 << 4) | ||
222 | #define PWM_MODE_OFF (2 << 4) | ||
223 | #define PWM_MODE_ON (7 << 4) | ||
224 | |||
225 | /* Dedicated function to read all registers related to a given PWM output. | ||
226 | This saves us quite a few locks and bank selections. | ||
227 | Must be called with data->lock held. | ||
228 | nr is from 0 to 3 */ | ||
229 | static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr) | ||
230 | { | ||
231 | int iobase = data->address[LD_FAN]; | ||
232 | |||
233 | outb(BANK_FC(nr), iobase + PC87427_REG_BANK); | ||
234 | data->pwm_enable[nr] = inb(iobase + PC87427_REG_PWM_ENABLE); | ||
235 | data->pwm[nr] = inb(iobase + PC87427_REG_PWM_DUTY); | ||
236 | } | ||
237 | |||
238 | static inline int pwm_enable_from_reg(u8 reg) | ||
239 | { | ||
240 | switch (reg & PWM_ENABLE_MODE_MASK) { | ||
241 | case PWM_MODE_ON: | ||
242 | return 0; | ||
243 | case PWM_MODE_MANUAL: | ||
244 | case PWM_MODE_OFF: | ||
245 | return 1; | ||
246 | case PWM_MODE_AUTO: | ||
247 | return 2; | ||
248 | default: | ||
249 | return -EPROTO; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval) | ||
254 | { | ||
255 | switch (val) { | ||
256 | default: | ||
257 | return PWM_MODE_ON; | ||
258 | case 1: | ||
259 | return pwmval ? PWM_MODE_MANUAL : PWM_MODE_OFF; | ||
260 | case 2: | ||
261 | return PWM_MODE_AUTO; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Temperature registers and conversions | ||
267 | */ | ||
268 | |||
269 | #define PC87427_REG_TEMP_STATUS 0x10 | ||
270 | #define PC87427_REG_TEMP 0x14 | ||
271 | #define PC87427_REG_TEMP_MAX 0x18 | ||
272 | #define PC87427_REG_TEMP_MIN 0x19 | ||
273 | #define PC87427_REG_TEMP_CRIT 0x1a | ||
274 | #define PC87427_REG_TEMP_TYPE 0x1d | ||
275 | |||
276 | #define TEMP_STATUS_CHANEN (1 << 0) | ||
277 | #define TEMP_STATUS_LOWFLG (1 << 1) | ||
278 | #define TEMP_STATUS_HIGHFLG (1 << 2) | ||
279 | #define TEMP_STATUS_CRITFLG (1 << 3) | ||
280 | #define TEMP_STATUS_SENSERR (1 << 5) | ||
281 | #define TEMP_TYPE_MASK (3 << 5) | ||
282 | |||
283 | #define TEMP_TYPE_THERMISTOR (1 << 5) | ||
284 | #define TEMP_TYPE_REMOTE_DIODE (2 << 5) | ||
285 | #define TEMP_TYPE_LOCAL_DIODE (3 << 5) | ||
286 | |||
287 | /* Dedicated function to read all registers related to a given temperature | ||
288 | input. This saves us quite a few locks and bank selections. | ||
289 | Must be called with data->lock held. | ||
290 | nr is from 0 to 5 */ | ||
291 | static void pc87427_readall_temp(struct pc87427_data *data, u8 nr) | ||
292 | { | ||
293 | int iobase = data->address[LD_TEMP]; | ||
294 | |||
295 | outb(BANK_TM(nr), iobase + PC87427_REG_BANK); | ||
296 | data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP)); | ||
297 | data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX); | ||
298 | data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN); | ||
299 | data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT); | ||
300 | data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE); | ||
301 | data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS); | ||
302 | /* Clear fan alarm bits */ | ||
303 | outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS); | ||
304 | } | ||
305 | |||
306 | static inline unsigned int temp_type_from_reg(u8 reg) | ||
307 | { | ||
308 | switch (reg & TEMP_TYPE_MASK) { | ||
309 | case TEMP_TYPE_THERMISTOR: | ||
310 | return 4; | ||
311 | case TEMP_TYPE_REMOTE_DIODE: | ||
312 | case TEMP_TYPE_LOCAL_DIODE: | ||
313 | return 3; | ||
314 | default: | ||
315 | return 0; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible | ||
320 | too, but I have no idea how to figure out when they are used. */ | ||
321 | static inline long temp_from_reg(s16 reg) | ||
322 | { | ||
323 | return reg * 1000 / 256; | ||
324 | } | ||
325 | |||
326 | static inline long temp_from_reg8(s8 reg) | ||
327 | { | ||
328 | return reg * 1000; | ||
329 | } | ||
330 | |||
331 | /* | ||
182 | * Data interface | 332 | * Data interface |
183 | */ | 333 | */ |
184 | 334 | ||
@@ -198,6 +348,21 @@ static struct pc87427_data *pc87427_update_device(struct device *dev) | |||
198 | continue; | 348 | continue; |
199 | pc87427_readall_fan(data, i); | 349 | pc87427_readall_fan(data, i); |
200 | } | 350 | } |
351 | |||
352 | /* PWM outputs */ | ||
353 | for (i = 0; i < 4; i++) { | ||
354 | if (!(data->pwm_enabled & (1 << i))) | ||
355 | continue; | ||
356 | pc87427_readall_pwm(data, i); | ||
357 | } | ||
358 | |||
359 | /* Temperature channels */ | ||
360 | for (i = 0; i < 6; i++) { | ||
361 | if (!(data->temp_enabled & (1 << i))) | ||
362 | continue; | ||
363 | pc87427_readall_temp(data, i); | ||
364 | } | ||
365 | |||
201 | data->last_updated = jiffies; | 366 | data->last_updated = jiffies; |
202 | 367 | ||
203 | done: | 368 | done: |
@@ -208,9 +373,8 @@ done: | |||
208 | static ssize_t show_fan_input(struct device *dev, struct device_attribute | 373 | static ssize_t show_fan_input(struct device *dev, struct device_attribute |
209 | *devattr, char *buf) | 374 | *devattr, char *buf) |
210 | { | 375 | { |
211 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
212 | struct pc87427_data *data = pc87427_update_device(dev); | 376 | struct pc87427_data *data = pc87427_update_device(dev); |
213 | int nr = attr->index; | 377 | int nr = to_sensor_dev_attr(devattr)->index; |
214 | 378 | ||
215 | return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr])); | 379 | return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr])); |
216 | } | 380 | } |
@@ -218,9 +382,8 @@ static ssize_t show_fan_input(struct device *dev, struct device_attribute | |||
218 | static ssize_t show_fan_min(struct device *dev, struct device_attribute | 382 | static ssize_t show_fan_min(struct device *dev, struct device_attribute |
219 | *devattr, char *buf) | 383 | *devattr, char *buf) |
220 | { | 384 | { |
221 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
222 | struct pc87427_data *data = pc87427_update_device(dev); | 385 | struct pc87427_data *data = pc87427_update_device(dev); |
223 | int nr = attr->index; | 386 | int nr = to_sensor_dev_attr(devattr)->index; |
224 | 387 | ||
225 | return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr])); | 388 | return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr])); |
226 | } | 389 | } |
@@ -228,9 +391,8 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute | |||
228 | static ssize_t show_fan_alarm(struct device *dev, struct device_attribute | 391 | static ssize_t show_fan_alarm(struct device *dev, struct device_attribute |
229 | *devattr, char *buf) | 392 | *devattr, char *buf) |
230 | { | 393 | { |
231 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
232 | struct pc87427_data *data = pc87427_update_device(dev); | 394 | struct pc87427_data *data = pc87427_update_device(dev); |
233 | int nr = attr->index; | 395 | int nr = to_sensor_dev_attr(devattr)->index; |
234 | 396 | ||
235 | return sprintf(buf, "%d\n", !!(data->fan_status[nr] | 397 | return sprintf(buf, "%d\n", !!(data->fan_status[nr] |
236 | & FAN_STATUS_LOSPD)); | 398 | & FAN_STATUS_LOSPD)); |
@@ -239,9 +401,8 @@ static ssize_t show_fan_alarm(struct device *dev, struct device_attribute | |||
239 | static ssize_t show_fan_fault(struct device *dev, struct device_attribute | 401 | static ssize_t show_fan_fault(struct device *dev, struct device_attribute |
240 | *devattr, char *buf) | 402 | *devattr, char *buf) |
241 | { | 403 | { |
242 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
243 | struct pc87427_data *data = pc87427_update_device(dev); | 404 | struct pc87427_data *data = pc87427_update_device(dev); |
244 | int nr = attr->index; | 405 | int nr = to_sensor_dev_attr(devattr)->index; |
245 | 406 | ||
246 | return sprintf(buf, "%d\n", !!(data->fan_status[nr] | 407 | return sprintf(buf, "%d\n", !!(data->fan_status[nr] |
247 | & FAN_STATUS_STALL)); | 408 | & FAN_STATUS_STALL)); |
@@ -251,11 +412,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
251 | *devattr, const char *buf, size_t count) | 412 | *devattr, const char *buf, size_t count) |
252 | { | 413 | { |
253 | struct pc87427_data *data = dev_get_drvdata(dev); | 414 | struct pc87427_data *data = dev_get_drvdata(dev); |
254 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 415 | int nr = to_sensor_dev_attr(devattr)->index; |
255 | int nr = attr->index; | 416 | unsigned long val; |
256 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
257 | int iobase = data->address[LD_FAN]; | 417 | int iobase = data->address[LD_FAN]; |
258 | 418 | ||
419 | if (strict_strtoul(buf, 10, &val) < 0) | ||
420 | return -EINVAL; | ||
421 | |||
259 | mutex_lock(&data->lock); | 422 | mutex_lock(&data->lock); |
260 | outb(BANK_FM(nr), iobase + PC87427_REG_BANK); | 423 | outb(BANK_FM(nr), iobase + PC87427_REG_BANK); |
261 | /* The low speed limit registers are read-only while monitoring | 424 | /* The low speed limit registers are read-only while monitoring |
@@ -377,6 +540,390 @@ static const struct attribute_group pc87427_group_fan[8] = { | |||
377 | { .attrs = pc87427_attributes_fan[7] }, | 540 | { .attrs = pc87427_attributes_fan[7] }, |
378 | }; | 541 | }; |
379 | 542 | ||
543 | /* Must be called with data->lock held and pc87427_readall_pwm() freshly | ||
544 | called */ | ||
545 | static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode) | ||
546 | { | ||
547 | int iobase = data->address[LD_FAN]; | ||
548 | data->pwm_enable[nr] &= ~PWM_ENABLE_MODE_MASK; | ||
549 | data->pwm_enable[nr] |= mode; | ||
550 | outb(data->pwm_enable[nr], iobase + PC87427_REG_PWM_ENABLE); | ||
551 | } | ||
552 | |||
553 | static ssize_t show_pwm_enable(struct device *dev, struct device_attribute | ||
554 | *devattr, char *buf) | ||
555 | { | ||
556 | struct pc87427_data *data = pc87427_update_device(dev); | ||
557 | int nr = to_sensor_dev_attr(devattr)->index; | ||
558 | int pwm_enable; | ||
559 | |||
560 | pwm_enable = pwm_enable_from_reg(data->pwm_enable[nr]); | ||
561 | if (pwm_enable < 0) | ||
562 | return pwm_enable; | ||
563 | return sprintf(buf, "%d\n", pwm_enable); | ||
564 | } | ||
565 | |||
566 | static ssize_t set_pwm_enable(struct device *dev, struct device_attribute | ||
567 | *devattr, const char *buf, size_t count) | ||
568 | { | ||
569 | struct pc87427_data *data = dev_get_drvdata(dev); | ||
570 | int nr = to_sensor_dev_attr(devattr)->index; | ||
571 | unsigned long val; | ||
572 | |||
573 | if (strict_strtoul(buf, 10, &val) < 0 || val > 2) | ||
574 | return -EINVAL; | ||
575 | /* Can't go to automatic mode if it isn't configured */ | ||
576 | if (val == 2 && !(data->pwm_auto_ok & (1 << nr))) | ||
577 | return -EINVAL; | ||
578 | |||
579 | mutex_lock(&data->lock); | ||
580 | pc87427_readall_pwm(data, nr); | ||
581 | update_pwm_enable(data, nr, pwm_enable_to_reg(val, data->pwm[nr])); | ||
582 | mutex_unlock(&data->lock); | ||
583 | |||
584 | return count; | ||
585 | } | ||
586 | |||
587 | static ssize_t show_pwm(struct device *dev, struct device_attribute | ||
588 | *devattr, char *buf) | ||
589 | { | ||
590 | struct pc87427_data *data = pc87427_update_device(dev); | ||
591 | int nr = to_sensor_dev_attr(devattr)->index; | ||
592 | |||
593 | return sprintf(buf, "%d\n", (int)data->pwm[nr]); | ||
594 | } | ||
595 | |||
596 | static ssize_t set_pwm(struct device *dev, struct device_attribute | ||
597 | *devattr, const char *buf, size_t count) | ||
598 | { | ||
599 | struct pc87427_data *data = dev_get_drvdata(dev); | ||
600 | int nr = to_sensor_dev_attr(devattr)->index; | ||
601 | unsigned long val; | ||
602 | int iobase = data->address[LD_FAN]; | ||
603 | u8 mode; | ||
604 | |||
605 | if (strict_strtoul(buf, 10, &val) < 0 || val > 0xff) | ||
606 | return -EINVAL; | ||
607 | |||
608 | mutex_lock(&data->lock); | ||
609 | pc87427_readall_pwm(data, nr); | ||
610 | mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK; | ||
611 | if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) { | ||
612 | dev_notice(dev, "Can't set PWM%d duty cycle while not in " | ||
613 | "manual mode\n", nr + 1); | ||
614 | mutex_unlock(&data->lock); | ||
615 | return -EPERM; | ||
616 | } | ||
617 | |||
618 | /* We may have to change the mode */ | ||
619 | if (mode == PWM_MODE_MANUAL && val == 0) { | ||
620 | /* Transition from Manual to Off */ | ||
621 | update_pwm_enable(data, nr, PWM_MODE_OFF); | ||
622 | mode = PWM_MODE_OFF; | ||
623 | dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1, | ||
624 | "manual", "off"); | ||
625 | } else if (mode == PWM_MODE_OFF && val != 0) { | ||
626 | /* Transition from Off to Manual */ | ||
627 | update_pwm_enable(data, nr, PWM_MODE_MANUAL); | ||
628 | mode = PWM_MODE_MANUAL; | ||
629 | dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1, | ||
630 | "off", "manual"); | ||
631 | } | ||
632 | |||
633 | data->pwm[nr] = val; | ||
634 | if (mode == PWM_MODE_MANUAL) | ||
635 | outb(val, iobase + PC87427_REG_PWM_DUTY); | ||
636 | mutex_unlock(&data->lock); | ||
637 | |||
638 | return count; | ||
639 | } | ||
640 | |||
641 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | ||
642 | show_pwm_enable, set_pwm_enable, 0); | ||
643 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, | ||
644 | show_pwm_enable, set_pwm_enable, 1); | ||
645 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, | ||
646 | show_pwm_enable, set_pwm_enable, 2); | ||
647 | static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, | ||
648 | show_pwm_enable, set_pwm_enable, 3); | ||
649 | |||
650 | static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); | ||
651 | static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); | ||
652 | static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); | ||
653 | static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); | ||
654 | |||
655 | static struct attribute *pc87427_attributes_pwm[4][3] = { | ||
656 | { | ||
657 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
658 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
659 | NULL | ||
660 | }, { | ||
661 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
662 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
663 | NULL | ||
664 | }, { | ||
665 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
666 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
667 | NULL | ||
668 | }, { | ||
669 | &sensor_dev_attr_pwm4_enable.dev_attr.attr, | ||
670 | &sensor_dev_attr_pwm4.dev_attr.attr, | ||
671 | NULL | ||
672 | } | ||
673 | }; | ||
674 | |||
675 | static const struct attribute_group pc87427_group_pwm[4] = { | ||
676 | { .attrs = pc87427_attributes_pwm[0] }, | ||
677 | { .attrs = pc87427_attributes_pwm[1] }, | ||
678 | { .attrs = pc87427_attributes_pwm[2] }, | ||
679 | { .attrs = pc87427_attributes_pwm[3] }, | ||
680 | }; | ||
681 | |||
682 | static ssize_t show_temp_input(struct device *dev, struct device_attribute | ||
683 | *devattr, char *buf) | ||
684 | { | ||
685 | struct pc87427_data *data = pc87427_update_device(dev); | ||
686 | int nr = to_sensor_dev_attr(devattr)->index; | ||
687 | |||
688 | return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr])); | ||
689 | } | ||
690 | |||
691 | static ssize_t show_temp_min(struct device *dev, struct device_attribute | ||
692 | *devattr, char *buf) | ||
693 | { | ||
694 | struct pc87427_data *data = pc87427_update_device(dev); | ||
695 | int nr = to_sensor_dev_attr(devattr)->index; | ||
696 | |||
697 | return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr])); | ||
698 | } | ||
699 | |||
700 | static ssize_t show_temp_max(struct device *dev, struct device_attribute | ||
701 | *devattr, char *buf) | ||
702 | { | ||
703 | struct pc87427_data *data = pc87427_update_device(dev); | ||
704 | int nr = to_sensor_dev_attr(devattr)->index; | ||
705 | |||
706 | return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr])); | ||
707 | } | ||
708 | |||
709 | static ssize_t show_temp_crit(struct device *dev, struct device_attribute | ||
710 | *devattr, char *buf) | ||
711 | { | ||
712 | struct pc87427_data *data = pc87427_update_device(dev); | ||
713 | int nr = to_sensor_dev_attr(devattr)->index; | ||
714 | |||
715 | return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr])); | ||
716 | } | ||
717 | |||
718 | static ssize_t show_temp_type(struct device *dev, struct device_attribute | ||
719 | *devattr, char *buf) | ||
720 | { | ||
721 | struct pc87427_data *data = pc87427_update_device(dev); | ||
722 | int nr = to_sensor_dev_attr(devattr)->index; | ||
723 | |||
724 | return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr])); | ||
725 | } | ||
726 | |||
727 | static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute | ||
728 | *devattr, char *buf) | ||
729 | { | ||
730 | struct pc87427_data *data = pc87427_update_device(dev); | ||
731 | int nr = to_sensor_dev_attr(devattr)->index; | ||
732 | |||
733 | return sprintf(buf, "%d\n", !!(data->temp_status[nr] | ||
734 | & TEMP_STATUS_LOWFLG)); | ||
735 | } | ||
736 | |||
737 | static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute | ||
738 | *devattr, char *buf) | ||
739 | { | ||
740 | struct pc87427_data *data = pc87427_update_device(dev); | ||
741 | int nr = to_sensor_dev_attr(devattr)->index; | ||
742 | |||
743 | return sprintf(buf, "%d\n", !!(data->temp_status[nr] | ||
744 | & TEMP_STATUS_HIGHFLG)); | ||
745 | } | ||
746 | |||
747 | static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute | ||
748 | *devattr, char *buf) | ||
749 | { | ||
750 | struct pc87427_data *data = pc87427_update_device(dev); | ||
751 | int nr = to_sensor_dev_attr(devattr)->index; | ||
752 | |||
753 | return sprintf(buf, "%d\n", !!(data->temp_status[nr] | ||
754 | & TEMP_STATUS_CRITFLG)); | ||
755 | } | ||
756 | |||
757 | static ssize_t show_temp_fault(struct device *dev, struct device_attribute | ||
758 | *devattr, char *buf) | ||
759 | { | ||
760 | struct pc87427_data *data = pc87427_update_device(dev); | ||
761 | int nr = to_sensor_dev_attr(devattr)->index; | ||
762 | |||
763 | return sprintf(buf, "%d\n", !!(data->temp_status[nr] | ||
764 | & TEMP_STATUS_SENSERR)); | ||
765 | } | ||
766 | |||
767 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); | ||
768 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1); | ||
769 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2); | ||
770 | static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3); | ||
771 | static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4); | ||
772 | static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5); | ||
773 | |||
774 | static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0); | ||
775 | static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1); | ||
776 | static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2); | ||
777 | static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3); | ||
778 | static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4); | ||
779 | static SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5); | ||
780 | |||
781 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0); | ||
782 | static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1); | ||
783 | static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2); | ||
784 | static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3); | ||
785 | static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4); | ||
786 | static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5); | ||
787 | |||
788 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); | ||
789 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1); | ||
790 | static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2); | ||
791 | static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3); | ||
792 | static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4); | ||
793 | static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5); | ||
794 | |||
795 | static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0); | ||
796 | static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1); | ||
797 | static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); | ||
798 | static SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3); | ||
799 | static SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4); | ||
800 | static SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5); | ||
801 | |||
802 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, | ||
803 | show_temp_min_alarm, NULL, 0); | ||
804 | static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, | ||
805 | show_temp_min_alarm, NULL, 1); | ||
806 | static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, | ||
807 | show_temp_min_alarm, NULL, 2); | ||
808 | static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, | ||
809 | show_temp_min_alarm, NULL, 3); | ||
810 | static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, | ||
811 | show_temp_min_alarm, NULL, 4); | ||
812 | static SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO, | ||
813 | show_temp_min_alarm, NULL, 5); | ||
814 | |||
815 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, | ||
816 | show_temp_max_alarm, NULL, 0); | ||
817 | static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, | ||
818 | show_temp_max_alarm, NULL, 1); | ||
819 | static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, | ||
820 | show_temp_max_alarm, NULL, 2); | ||
821 | static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, | ||
822 | show_temp_max_alarm, NULL, 3); | ||
823 | static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, | ||
824 | show_temp_max_alarm, NULL, 4); | ||
825 | static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, | ||
826 | show_temp_max_alarm, NULL, 5); | ||
827 | |||
828 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, | ||
829 | show_temp_crit_alarm, NULL, 0); | ||
830 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, | ||
831 | show_temp_crit_alarm, NULL, 1); | ||
832 | static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, | ||
833 | show_temp_crit_alarm, NULL, 2); | ||
834 | static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, | ||
835 | show_temp_crit_alarm, NULL, 3); | ||
836 | static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, | ||
837 | show_temp_crit_alarm, NULL, 4); | ||
838 | static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, | ||
839 | show_temp_crit_alarm, NULL, 5); | ||
840 | |||
841 | static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0); | ||
842 | static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1); | ||
843 | static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2); | ||
844 | static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3); | ||
845 | static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4); | ||
846 | static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5); | ||
847 | |||
848 | static struct attribute *pc87427_attributes_temp[6][10] = { | ||
849 | { | ||
850 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
851 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
852 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
853 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
854 | &sensor_dev_attr_temp1_type.dev_attr.attr, | ||
855 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
856 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
857 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | ||
858 | &sensor_dev_attr_temp1_fault.dev_attr.attr, | ||
859 | NULL | ||
860 | }, { | ||
861 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
862 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
863 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
864 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
865 | &sensor_dev_attr_temp2_type.dev_attr.attr, | ||
866 | &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, | ||
867 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | ||
868 | &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, | ||
869 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | ||
870 | NULL | ||
871 | }, { | ||
872 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
873 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
874 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
875 | &sensor_dev_attr_temp3_crit.dev_attr.attr, | ||
876 | &sensor_dev_attr_temp3_type.dev_attr.attr, | ||
877 | &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, | ||
878 | &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, | ||
879 | &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, | ||
880 | &sensor_dev_attr_temp3_fault.dev_attr.attr, | ||
881 | NULL | ||
882 | }, { | ||
883 | &sensor_dev_attr_temp4_input.dev_attr.attr, | ||
884 | &sensor_dev_attr_temp4_min.dev_attr.attr, | ||
885 | &sensor_dev_attr_temp4_max.dev_attr.attr, | ||
886 | &sensor_dev_attr_temp4_crit.dev_attr.attr, | ||
887 | &sensor_dev_attr_temp4_type.dev_attr.attr, | ||
888 | &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, | ||
889 | &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, | ||
890 | &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, | ||
891 | &sensor_dev_attr_temp4_fault.dev_attr.attr, | ||
892 | NULL | ||
893 | }, { | ||
894 | &sensor_dev_attr_temp5_input.dev_attr.attr, | ||
895 | &sensor_dev_attr_temp5_min.dev_attr.attr, | ||
896 | &sensor_dev_attr_temp5_max.dev_attr.attr, | ||
897 | &sensor_dev_attr_temp5_crit.dev_attr.attr, | ||
898 | &sensor_dev_attr_temp5_type.dev_attr.attr, | ||
899 | &sensor_dev_attr_temp5_min_alarm.dev_attr.attr, | ||
900 | &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, | ||
901 | &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, | ||
902 | &sensor_dev_attr_temp5_fault.dev_attr.attr, | ||
903 | NULL | ||
904 | }, { | ||
905 | &sensor_dev_attr_temp6_input.dev_attr.attr, | ||
906 | &sensor_dev_attr_temp6_min.dev_attr.attr, | ||
907 | &sensor_dev_attr_temp6_max.dev_attr.attr, | ||
908 | &sensor_dev_attr_temp6_crit.dev_attr.attr, | ||
909 | &sensor_dev_attr_temp6_type.dev_attr.attr, | ||
910 | &sensor_dev_attr_temp6_min_alarm.dev_attr.attr, | ||
911 | &sensor_dev_attr_temp6_max_alarm.dev_attr.attr, | ||
912 | &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr, | ||
913 | &sensor_dev_attr_temp6_fault.dev_attr.attr, | ||
914 | NULL | ||
915 | } | ||
916 | }; | ||
917 | |||
918 | static const struct attribute_group pc87427_group_temp[6] = { | ||
919 | { .attrs = pc87427_attributes_temp[0] }, | ||
920 | { .attrs = pc87427_attributes_temp[1] }, | ||
921 | { .attrs = pc87427_attributes_temp[2] }, | ||
922 | { .attrs = pc87427_attributes_temp[3] }, | ||
923 | { .attrs = pc87427_attributes_temp[4] }, | ||
924 | { .attrs = pc87427_attributes_temp[5] }, | ||
925 | }; | ||
926 | |||
380 | static ssize_t show_name(struct device *dev, struct device_attribute | 927 | static ssize_t show_name(struct device *dev, struct device_attribute |
381 | *devattr, char *buf) | 928 | *devattr, char *buf) |
382 | { | 929 | { |
@@ -391,8 +938,49 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | |||
391 | * Device detection, attach and detach | 938 | * Device detection, attach and detach |
392 | */ | 939 | */ |
393 | 940 | ||
941 | static void pc87427_release_regions(struct platform_device *pdev, int count) | ||
942 | { | ||
943 | struct resource *res; | ||
944 | int i; | ||
945 | |||
946 | for (i = 0; i < count; i++) { | ||
947 | res = platform_get_resource(pdev, IORESOURCE_IO, i); | ||
948 | release_region(res->start, resource_size(res)); | ||
949 | } | ||
950 | } | ||
951 | |||
952 | static int __devinit pc87427_request_regions(struct platform_device *pdev, | ||
953 | int count) | ||
954 | { | ||
955 | struct resource *res; | ||
956 | int i, err = 0; | ||
957 | |||
958 | for (i = 0; i < count; i++) { | ||
959 | res = platform_get_resource(pdev, IORESOURCE_IO, i); | ||
960 | if (!res) { | ||
961 | err = -ENOENT; | ||
962 | dev_err(&pdev->dev, "Missing resource #%d\n", i); | ||
963 | break; | ||
964 | } | ||
965 | if (!request_region(res->start, resource_size(res), DRVNAME)) { | ||
966 | err = -EBUSY; | ||
967 | dev_err(&pdev->dev, | ||
968 | "Failed to request region 0x%lx-0x%lx\n", | ||
969 | (unsigned long)res->start, | ||
970 | (unsigned long)res->end); | ||
971 | break; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | if (err && i) | ||
976 | pc87427_release_regions(pdev, i); | ||
977 | |||
978 | return err; | ||
979 | } | ||
980 | |||
394 | static void __devinit pc87427_init_device(struct device *dev) | 981 | static void __devinit pc87427_init_device(struct device *dev) |
395 | { | 982 | { |
983 | struct pc87427_sio_data *sio_data = dev->platform_data; | ||
396 | struct pc87427_data *data = dev_get_drvdata(dev); | 984 | struct pc87427_data *data = dev_get_drvdata(dev); |
397 | int i; | 985 | int i; |
398 | u8 reg; | 986 | u8 reg; |
@@ -400,10 +988,12 @@ static void __devinit pc87427_init_device(struct device *dev) | |||
400 | /* The FMC module should be ready */ | 988 | /* The FMC module should be ready */ |
401 | reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK); | 989 | reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK); |
402 | if (!(reg & 0x80)) | 990 | if (!(reg & 0x80)) |
403 | dev_warn(dev, "FMC module not ready!\n"); | 991 | dev_warn(dev, "%s module not ready!\n", "FMC"); |
404 | 992 | ||
405 | /* Check which fans are enabled */ | 993 | /* Check which fans are enabled */ |
406 | for (i = 0; i < 8; i++) { | 994 | for (i = 0; i < 8; i++) { |
995 | if (!(sio_data->has_fanin & (1 << i))) /* Not wired */ | ||
996 | continue; | ||
407 | reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i), | 997 | reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i), |
408 | PC87427_REG_FAN_STATUS); | 998 | PC87427_REG_FAN_STATUS); |
409 | if (reg & FAN_STATUS_MONEN) | 999 | if (reg & FAN_STATUS_MONEN) |
@@ -411,37 +1001,93 @@ static void __devinit pc87427_init_device(struct device *dev) | |||
411 | } | 1001 | } |
412 | 1002 | ||
413 | if (!data->fan_enabled) { | 1003 | if (!data->fan_enabled) { |
414 | dev_dbg(dev, "Enabling all fan inputs\n"); | 1004 | dev_dbg(dev, "Enabling monitoring of all fans\n"); |
415 | for (i = 0; i < 8; i++) | 1005 | for (i = 0; i < 8; i++) { |
1006 | if (!(sio_data->has_fanin & (1 << i))) /* Not wired */ | ||
1007 | continue; | ||
416 | pc87427_write8_bank(data, LD_FAN, BANK_FM(i), | 1008 | pc87427_write8_bank(data, LD_FAN, BANK_FM(i), |
417 | PC87427_REG_FAN_STATUS, | 1009 | PC87427_REG_FAN_STATUS, |
418 | FAN_STATUS_MONEN); | 1010 | FAN_STATUS_MONEN); |
419 | data->fan_enabled = 0xff; | 1011 | } |
1012 | data->fan_enabled = sio_data->has_fanin; | ||
1013 | } | ||
1014 | |||
1015 | /* Check which PWM outputs are enabled */ | ||
1016 | for (i = 0; i < 4; i++) { | ||
1017 | if (!(sio_data->has_fanout & (1 << i))) /* Not wired */ | ||
1018 | continue; | ||
1019 | reg = pc87427_read8_bank(data, LD_FAN, BANK_FC(i), | ||
1020 | PC87427_REG_PWM_ENABLE); | ||
1021 | if (reg & PWM_ENABLE_CTLEN) | ||
1022 | data->pwm_enabled |= (1 << i); | ||
1023 | |||
1024 | /* We don't expose an interface to reconfigure the automatic | ||
1025 | fan control mode, so only allow to return to this mode if | ||
1026 | it was originally set. */ | ||
1027 | if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) { | ||
1028 | dev_dbg(dev, "PWM%d is in automatic control mode\n", | ||
1029 | i + 1); | ||
1030 | data->pwm_auto_ok |= (1 << i); | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | /* The HMC module should be ready */ | ||
1035 | reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK); | ||
1036 | if (!(reg & 0x80)) | ||
1037 | dev_warn(dev, "%s module not ready!\n", "HMC"); | ||
1038 | |||
1039 | /* Check which temperature channels are enabled */ | ||
1040 | for (i = 0; i < 6; i++) { | ||
1041 | reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i), | ||
1042 | PC87427_REG_TEMP_STATUS); | ||
1043 | if (reg & TEMP_STATUS_CHANEN) | ||
1044 | data->temp_enabled |= (1 << i); | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | static void pc87427_remove_files(struct device *dev) | ||
1049 | { | ||
1050 | struct pc87427_data *data = dev_get_drvdata(dev); | ||
1051 | int i; | ||
1052 | |||
1053 | device_remove_file(dev, &dev_attr_name); | ||
1054 | for (i = 0; i < 8; i++) { | ||
1055 | if (!(data->fan_enabled & (1 << i))) | ||
1056 | continue; | ||
1057 | sysfs_remove_group(&dev->kobj, &pc87427_group_fan[i]); | ||
1058 | } | ||
1059 | for (i = 0; i < 4; i++) { | ||
1060 | if (!(data->pwm_enabled & (1 << i))) | ||
1061 | continue; | ||
1062 | sysfs_remove_group(&dev->kobj, &pc87427_group_pwm[i]); | ||
1063 | } | ||
1064 | for (i = 0; i < 6; i++) { | ||
1065 | if (!(data->temp_enabled & (1 << i))) | ||
1066 | continue; | ||
1067 | sysfs_remove_group(&dev->kobj, &pc87427_group_temp[i]); | ||
420 | } | 1068 | } |
421 | } | 1069 | } |
422 | 1070 | ||
423 | static int __devinit pc87427_probe(struct platform_device *pdev) | 1071 | static int __devinit pc87427_probe(struct platform_device *pdev) |
424 | { | 1072 | { |
1073 | struct pc87427_sio_data *sio_data = pdev->dev.platform_data; | ||
425 | struct pc87427_data *data; | 1074 | struct pc87427_data *data; |
426 | struct resource *res; | 1075 | int i, err, res_count; |
427 | int i, err; | ||
428 | 1076 | ||
429 | if (!(data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL))) { | 1077 | data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL); |
1078 | if (!data) { | ||
430 | err = -ENOMEM; | 1079 | err = -ENOMEM; |
431 | printk(KERN_ERR DRVNAME ": Out of memory\n"); | 1080 | printk(KERN_ERR DRVNAME ": Out of memory\n"); |
432 | goto exit; | 1081 | goto exit; |
433 | } | 1082 | } |
434 | 1083 | ||
435 | /* This will need to be revisited when we add support for | 1084 | data->address[0] = sio_data->address[0]; |
436 | temperature and voltage monitoring. */ | 1085 | data->address[1] = sio_data->address[1]; |
437 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1086 | res_count = (data->address[0] != 0) + (data->address[1] != 0); |
438 | if (!request_region(res->start, resource_size(res), DRVNAME)) { | 1087 | |
439 | err = -EBUSY; | 1088 | err = pc87427_request_regions(pdev, res_count); |
440 | dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", | 1089 | if (err) |
441 | (unsigned long)res->start, (unsigned long)res->end); | ||
442 | goto exit_kfree; | 1090 | goto exit_kfree; |
443 | } | ||
444 | data->address[0] = res->start; | ||
445 | 1091 | ||
446 | mutex_init(&data->lock); | 1092 | mutex_init(&data->lock); |
447 | data->name = "pc87427"; | 1093 | data->name = "pc87427"; |
@@ -449,13 +1095,31 @@ static int __devinit pc87427_probe(struct platform_device *pdev) | |||
449 | pc87427_init_device(&pdev->dev); | 1095 | pc87427_init_device(&pdev->dev); |
450 | 1096 | ||
451 | /* Register sysfs hooks */ | 1097 | /* Register sysfs hooks */ |
452 | if ((err = device_create_file(&pdev->dev, &dev_attr_name))) | 1098 | err = device_create_file(&pdev->dev, &dev_attr_name); |
1099 | if (err) | ||
453 | goto exit_release_region; | 1100 | goto exit_release_region; |
454 | for (i = 0; i < 8; i++) { | 1101 | for (i = 0; i < 8; i++) { |
455 | if (!(data->fan_enabled & (1 << i))) | 1102 | if (!(data->fan_enabled & (1 << i))) |
456 | continue; | 1103 | continue; |
457 | if ((err = sysfs_create_group(&pdev->dev.kobj, | 1104 | err = sysfs_create_group(&pdev->dev.kobj, |
458 | &pc87427_group_fan[i]))) | 1105 | &pc87427_group_fan[i]); |
1106 | if (err) | ||
1107 | goto exit_remove_files; | ||
1108 | } | ||
1109 | for (i = 0; i < 4; i++) { | ||
1110 | if (!(data->pwm_enabled & (1 << i))) | ||
1111 | continue; | ||
1112 | err = sysfs_create_group(&pdev->dev.kobj, | ||
1113 | &pc87427_group_pwm[i]); | ||
1114 | if (err) | ||
1115 | goto exit_remove_files; | ||
1116 | } | ||
1117 | for (i = 0; i < 6; i++) { | ||
1118 | if (!(data->temp_enabled & (1 << i))) | ||
1119 | continue; | ||
1120 | err = sysfs_create_group(&pdev->dev.kobj, | ||
1121 | &pc87427_group_temp[i]); | ||
1122 | if (err) | ||
459 | goto exit_remove_files; | 1123 | goto exit_remove_files; |
460 | } | 1124 | } |
461 | 1125 | ||
@@ -469,13 +1133,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev) | |||
469 | return 0; | 1133 | return 0; |
470 | 1134 | ||
471 | exit_remove_files: | 1135 | exit_remove_files: |
472 | for (i = 0; i < 8; i++) { | 1136 | pc87427_remove_files(&pdev->dev); |
473 | if (!(data->fan_enabled & (1 << i))) | ||
474 | continue; | ||
475 | sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); | ||
476 | } | ||
477 | exit_release_region: | 1137 | exit_release_region: |
478 | release_region(res->start, resource_size(res)); | 1138 | pc87427_release_regions(pdev, res_count); |
479 | exit_kfree: | 1139 | exit_kfree: |
480 | platform_set_drvdata(pdev, NULL); | 1140 | platform_set_drvdata(pdev, NULL); |
481 | kfree(data); | 1141 | kfree(data); |
@@ -486,21 +1146,16 @@ exit: | |||
486 | static int __devexit pc87427_remove(struct platform_device *pdev) | 1146 | static int __devexit pc87427_remove(struct platform_device *pdev) |
487 | { | 1147 | { |
488 | struct pc87427_data *data = platform_get_drvdata(pdev); | 1148 | struct pc87427_data *data = platform_get_drvdata(pdev); |
489 | struct resource *res; | 1149 | int res_count; |
490 | int i; | 1150 | |
1151 | res_count = (data->address[0] != 0) + (data->address[1] != 0); | ||
491 | 1152 | ||
492 | hwmon_device_unregister(data->hwmon_dev); | 1153 | hwmon_device_unregister(data->hwmon_dev); |
493 | device_remove_file(&pdev->dev, &dev_attr_name); | 1154 | pc87427_remove_files(&pdev->dev); |
494 | for (i = 0; i < 8; i++) { | ||
495 | if (!(data->fan_enabled & (1 << i))) | ||
496 | continue; | ||
497 | sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); | ||
498 | } | ||
499 | platform_set_drvdata(pdev, NULL); | 1155 | platform_set_drvdata(pdev, NULL); |
500 | kfree(data); | 1156 | kfree(data); |
501 | 1157 | ||
502 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1158 | pc87427_release_regions(pdev, res_count); |
503 | release_region(res->start, resource_size(res)); | ||
504 | 1159 | ||
505 | return 0; | 1160 | return 0; |
506 | } | 1161 | } |
@@ -515,34 +1170,50 @@ static struct platform_driver pc87427_driver = { | |||
515 | .remove = __devexit_p(pc87427_remove), | 1170 | .remove = __devexit_p(pc87427_remove), |
516 | }; | 1171 | }; |
517 | 1172 | ||
518 | static int __init pc87427_device_add(unsigned short address) | 1173 | static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) |
519 | { | 1174 | { |
520 | struct resource res = { | 1175 | struct resource res[2] = { |
521 | .start = address, | 1176 | { .flags = IORESOURCE_IO }, |
522 | .end = address + REGION_LENGTH - 1, | 1177 | { .flags = IORESOURCE_IO }, |
523 | .name = logdev_str[0], | ||
524 | .flags = IORESOURCE_IO, | ||
525 | }; | 1178 | }; |
526 | int err; | 1179 | int err, i, res_count; |
527 | 1180 | ||
528 | err = acpi_check_resource_conflict(&res); | 1181 | res_count = 0; |
529 | if (err) | 1182 | for (i = 0; i < 2; i++) { |
530 | goto exit; | 1183 | if (!sio_data->address[i]) |
1184 | continue; | ||
1185 | res[res_count].start = sio_data->address[i]; | ||
1186 | res[res_count].end = sio_data->address[i] + REGION_LENGTH - 1; | ||
1187 | res[res_count].name = logdev_str[i]; | ||
531 | 1188 | ||
532 | pdev = platform_device_alloc(DRVNAME, address); | 1189 | err = acpi_check_resource_conflict(&res[res_count]); |
1190 | if (err) | ||
1191 | goto exit; | ||
1192 | |||
1193 | res_count++; | ||
1194 | } | ||
1195 | |||
1196 | pdev = platform_device_alloc(DRVNAME, res[0].start); | ||
533 | if (!pdev) { | 1197 | if (!pdev) { |
534 | err = -ENOMEM; | 1198 | err = -ENOMEM; |
535 | printk(KERN_ERR DRVNAME ": Device allocation failed\n"); | 1199 | printk(KERN_ERR DRVNAME ": Device allocation failed\n"); |
536 | goto exit; | 1200 | goto exit; |
537 | } | 1201 | } |
538 | 1202 | ||
539 | err = platform_device_add_resources(pdev, &res, 1); | 1203 | err = platform_device_add_resources(pdev, res, res_count); |
540 | if (err) { | 1204 | if (err) { |
541 | printk(KERN_ERR DRVNAME ": Device resource addition failed " | 1205 | printk(KERN_ERR DRVNAME ": Device resource addition failed " |
542 | "(%d)\n", err); | 1206 | "(%d)\n", err); |
543 | goto exit_device_put; | 1207 | goto exit_device_put; |
544 | } | 1208 | } |
545 | 1209 | ||
1210 | err = platform_device_add_data(pdev, sio_data, | ||
1211 | sizeof(struct pc87427_sio_data)); | ||
1212 | if (err) { | ||
1213 | printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); | ||
1214 | goto exit_device_put; | ||
1215 | } | ||
1216 | |||
546 | err = platform_device_add(pdev); | 1217 | err = platform_device_add(pdev); |
547 | if (err) { | 1218 | if (err) { |
548 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", | 1219 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", |
@@ -558,9 +1229,10 @@ exit: | |||
558 | return err; | 1229 | return err; |
559 | } | 1230 | } |
560 | 1231 | ||
561 | static int __init pc87427_find(int sioaddr, unsigned short *address) | 1232 | static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data) |
562 | { | 1233 | { |
563 | u16 val; | 1234 | u16 val; |
1235 | u8 cfg, cfg_b; | ||
564 | int i, err = 0; | 1236 | int i, err = 0; |
565 | 1237 | ||
566 | /* Identify device */ | 1238 | /* Identify device */ |
@@ -571,7 +1243,7 @@ static int __init pc87427_find(int sioaddr, unsigned short *address) | |||
571 | } | 1243 | } |
572 | 1244 | ||
573 | for (i = 0; i < 2; i++) { | 1245 | for (i = 0; i < 2; i++) { |
574 | address[i] = 0; | 1246 | sio_data->address[i] = 0; |
575 | /* Select logical device */ | 1247 | /* Select logical device */ |
576 | superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]); | 1248 | superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]); |
577 | 1249 | ||
@@ -596,9 +1268,58 @@ static int __init pc87427_find(int sioaddr, unsigned short *address) | |||
596 | "for logical device 0x%02x\n", logdev[i]); | 1268 | "for logical device 0x%02x\n", logdev[i]); |
597 | continue; | 1269 | continue; |
598 | } | 1270 | } |
599 | address[i] = val; | 1271 | sio_data->address[i] = val; |
600 | } | 1272 | } |
601 | 1273 | ||
1274 | /* No point in loading the driver if everything is disabled */ | ||
1275 | if (!sio_data->address[0] && !sio_data->address[1]) { | ||
1276 | err = -ENODEV; | ||
1277 | goto exit; | ||
1278 | } | ||
1279 | |||
1280 | /* Check which fan inputs are wired */ | ||
1281 | sio_data->has_fanin = (1 << 2) | (1 << 3); /* FANIN2, FANIN3 */ | ||
1282 | |||
1283 | cfg = superio_inb(sioaddr, SIOREG_CF2); | ||
1284 | if (!(cfg & (1 << 3))) | ||
1285 | sio_data->has_fanin |= (1 << 0); /* FANIN0 */ | ||
1286 | if (!(cfg & (1 << 2))) | ||
1287 | sio_data->has_fanin |= (1 << 4); /* FANIN4 */ | ||
1288 | |||
1289 | cfg = superio_inb(sioaddr, SIOREG_CFD); | ||
1290 | if (!(cfg & (1 << 0))) | ||
1291 | sio_data->has_fanin |= (1 << 1); /* FANIN1 */ | ||
1292 | |||
1293 | cfg = superio_inb(sioaddr, SIOREG_CF4); | ||
1294 | if (!(cfg & (1 << 0))) | ||
1295 | sio_data->has_fanin |= (1 << 7); /* FANIN7 */ | ||
1296 | cfg_b = superio_inb(sioaddr, SIOREG_CFB); | ||
1297 | if (!(cfg & (1 << 1)) && (cfg_b & (1 << 3))) | ||
1298 | sio_data->has_fanin |= (1 << 5); /* FANIN5 */ | ||
1299 | cfg = superio_inb(sioaddr, SIOREG_CF3); | ||
1300 | if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5))) | ||
1301 | sio_data->has_fanin |= (1 << 6); /* FANIN6 */ | ||
1302 | |||
1303 | /* Check which fan outputs are wired */ | ||
1304 | sio_data->has_fanout = (1 << 0); /* FANOUT0 */ | ||
1305 | if (cfg_b & (1 << 0)) | ||
1306 | sio_data->has_fanout |= (1 << 3); /* FANOUT3 */ | ||
1307 | |||
1308 | cfg = superio_inb(sioaddr, SIOREG_CFC); | ||
1309 | if (!(cfg & (1 << 4))) { | ||
1310 | if (cfg_b & (1 << 1)) | ||
1311 | sio_data->has_fanout |= (1 << 1); /* FANOUT1 */ | ||
1312 | if (cfg_b & (1 << 2)) | ||
1313 | sio_data->has_fanout |= (1 << 2); /* FANOUT2 */ | ||
1314 | } | ||
1315 | |||
1316 | /* FANOUT1 and FANOUT2 can each be routed to 2 different pins */ | ||
1317 | cfg = superio_inb(sioaddr, SIOREG_CF5); | ||
1318 | if (cfg & (1 << 6)) | ||
1319 | sio_data->has_fanout |= (1 << 1); /* FANOUT1 */ | ||
1320 | if (cfg & (1 << 5)) | ||
1321 | sio_data->has_fanout |= (1 << 2); /* FANOUT2 */ | ||
1322 | |||
602 | exit: | 1323 | exit: |
603 | superio_exit(sioaddr); | 1324 | superio_exit(sioaddr); |
604 | return err; | 1325 | return err; |
@@ -607,15 +1328,10 @@ exit: | |||
607 | static int __init pc87427_init(void) | 1328 | static int __init pc87427_init(void) |
608 | { | 1329 | { |
609 | int err; | 1330 | int err; |
610 | unsigned short address[2]; | 1331 | struct pc87427_sio_data sio_data; |
611 | |||
612 | if (pc87427_find(0x2e, address) | ||
613 | && pc87427_find(0x4e, address)) | ||
614 | return -ENODEV; | ||
615 | 1332 | ||
616 | /* For now the driver only handles fans so we only care about the | 1333 | if (pc87427_find(0x2e, &sio_data) |
617 | first address. */ | 1334 | && pc87427_find(0x4e, &sio_data)) |
618 | if (!address[0]) | ||
619 | return -ENODEV; | 1335 | return -ENODEV; |
620 | 1336 | ||
621 | err = platform_driver_register(&pc87427_driver); | 1337 | err = platform_driver_register(&pc87427_driver); |
@@ -623,7 +1339,7 @@ static int __init pc87427_init(void) | |||
623 | goto exit; | 1339 | goto exit; |
624 | 1340 | ||
625 | /* Sets global pdev as a side effect */ | 1341 | /* Sets global pdev as a side effect */ |
626 | err = pc87427_device_add(address[0]); | 1342 | err = pc87427_device_add(&sio_data); |
627 | if (err) | 1343 | if (err) |
628 | goto exit_driver; | 1344 | goto exit_driver; |
629 | 1345 | ||