diff options
-rw-r--r-- | drivers/hwmon/smsc47m1.c | 166 |
1 files changed, 104 insertions, 62 deletions
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index aba11e56e8e7..c590c1469793 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c | |||
@@ -1,30 +1,30 @@ | |||
1 | /* | 1 | /* |
2 | smsc47m1.c - Part of lm_sensors, Linux kernel modules | 2 | * smsc47m1.c - Part of lm_sensors, Linux kernel modules |
3 | for hardware monitoring | 3 | * for hardware monitoring |
4 | 4 | * | |
5 | Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, | 5 | * Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, |
6 | LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 | 6 | * LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 |
7 | Super-I/O chips. | 7 | * Super-I/O chips. |
8 | 8 | * | |
9 | Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> | 9 | * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> |
10 | Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> | 10 | * Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> |
11 | Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> | 11 | * Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> |
12 | and Jean Delvare | 12 | * and Jean Delvare |
13 | 13 | * | |
14 | This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
16 | the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
17 | (at your option) any later version. | 17 | * (at your option) any later version. |
18 | 18 | * | |
19 | This program is distributed in the hope that it will be useful, | 19 | * This program is distributed in the hope that it will be useful, |
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
23 | 23 | * | |
24 | You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
25 | along with this program; if not, write to the Free Software | 25 | * along with this program; if not, write to the Free Software |
26 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
30 | 30 | ||
@@ -53,8 +53,8 @@ enum chips { smsc47m1, smsc47m2 }; | |||
53 | 53 | ||
54 | /* Super-I/0 registers and commands */ | 54 | /* Super-I/0 registers and commands */ |
55 | 55 | ||
56 | #define REG 0x2e /* The register to read/write */ | 56 | #define REG 0x2e /* The register to read/write */ |
57 | #define VAL 0x2f /* The value to read/write */ | 57 | #define VAL 0x2f /* The value to read/write */ |
58 | 58 | ||
59 | static inline void | 59 | static inline void |
60 | superio_outb(int reg, int val) | 60 | superio_outb(int reg, int val) |
@@ -111,10 +111,11 @@ static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; | |||
111 | #define SMSC47M2_REG_PPIN3 0x2c | 111 | #define SMSC47M2_REG_PPIN3 0x2c |
112 | #define SMSC47M2_REG_FANDIV3 0x6a | 112 | #define SMSC47M2_REG_FANDIV3 0x6a |
113 | 113 | ||
114 | #define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ | 114 | #define MIN_FROM_REG(reg, div) ((reg) >= 192 ? 0 : \ |
115 | 983040/((192-(reg))*(div))) | 115 | 983040 / ((192 - (reg)) * (div))) |
116 | #define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ | 116 | #define FAN_FROM_REG(reg, div, preload) ((reg) <= (preload) || (reg) == 255 ? \ |
117 | 983040/(((reg)-(preload))*(div))) | 117 | 0 : \ |
118 | 983040 / (((reg) - (preload)) * (div))) | ||
118 | #define DIV_FROM_REG(reg) (1 << (reg)) | 119 | #define DIV_FROM_REG(reg) (1 << (reg)) |
119 | #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) | 120 | #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) |
120 | #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) | 121 | #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) |
@@ -171,10 +172,12 @@ static ssize_t get_fan(struct device *dev, struct device_attribute | |||
171 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 172 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
172 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); | 173 | struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); |
173 | int nr = attr->index; | 174 | int nr = attr->index; |
174 | /* This chip (stupidly) stops monitoring fan speed if PWM is | 175 | /* |
175 | enabled and duty cycle is 0%. This is fine if the monitoring | 176 | * This chip (stupidly) stops monitoring fan speed if PWM is |
176 | and control concern the same fan, but troublesome if they are | 177 | * enabled and duty cycle is 0%. This is fine if the monitoring |
177 | not (which could as well happen). */ | 178 | * and control concern the same fan, but troublesome if they are |
179 | * not (which could as well happen). | ||
180 | */ | ||
178 | int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : | 181 | int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : |
179 | FAN_FROM_REG(data->fan[nr], | 182 | FAN_FROM_REG(data->fan[nr], |
180 | DIV_FROM_REG(data->fan_div[nr]), | 183 | DIV_FROM_REG(data->fan_div[nr]), |
@@ -238,7 +241,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
238 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 241 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
239 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 242 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
240 | int nr = attr->index; | 243 | int nr = attr->index; |
241 | long rpmdiv, val = simple_strtol(buf, NULL, 10); | 244 | long rpmdiv; |
245 | long val; | ||
246 | int err; | ||
247 | |||
248 | err = kstrtol(buf, 10, &val); | ||
249 | if (err) | ||
250 | return err; | ||
242 | 251 | ||
243 | mutex_lock(&data->update_lock); | 252 | mutex_lock(&data->update_lock); |
244 | rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); | 253 | rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); |
@@ -256,28 +265,44 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute | |||
256 | return count; | 265 | return count; |
257 | } | 266 | } |
258 | 267 | ||
259 | /* Note: we save and restore the fan minimum here, because its value is | 268 | /* |
260 | determined in part by the fan clock divider. This follows the principle | 269 | * Note: we save and restore the fan minimum here, because its value is |
261 | of least surprise; the user doesn't expect the fan minimum to change just | 270 | * determined in part by the fan clock divider. This follows the principle |
262 | because the divider changed. */ | 271 | * of least surprise; the user doesn't expect the fan minimum to change just |
272 | * because the divider changed. | ||
273 | */ | ||
263 | static ssize_t set_fan_div(struct device *dev, struct device_attribute | 274 | static ssize_t set_fan_div(struct device *dev, struct device_attribute |
264 | *devattr, const char *buf, size_t count) | 275 | *devattr, const char *buf, size_t count) |
265 | { | 276 | { |
266 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 277 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
267 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 278 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
268 | int nr = attr->index; | 279 | int nr = attr->index; |
269 | long new_div = simple_strtol(buf, NULL, 10), tmp; | 280 | long new_div; |
281 | int err; | ||
282 | long tmp; | ||
270 | u8 old_div = DIV_FROM_REG(data->fan_div[nr]); | 283 | u8 old_div = DIV_FROM_REG(data->fan_div[nr]); |
271 | 284 | ||
285 | err = kstrtol(buf, 10, &new_div); | ||
286 | if (err) | ||
287 | return err; | ||
288 | |||
272 | if (new_div == old_div) /* No change */ | 289 | if (new_div == old_div) /* No change */ |
273 | return count; | 290 | return count; |
274 | 291 | ||
275 | mutex_lock(&data->update_lock); | 292 | mutex_lock(&data->update_lock); |
276 | switch (new_div) { | 293 | switch (new_div) { |
277 | case 1: data->fan_div[nr] = 0; break; | 294 | case 1: |
278 | case 2: data->fan_div[nr] = 1; break; | 295 | data->fan_div[nr] = 0; |
279 | case 4: data->fan_div[nr] = 2; break; | 296 | break; |
280 | case 8: data->fan_div[nr] = 3; break; | 297 | case 2: |
298 | data->fan_div[nr] = 1; | ||
299 | break; | ||
300 | case 4: | ||
301 | data->fan_div[nr] = 2; | ||
302 | break; | ||
303 | case 8: | ||
304 | data->fan_div[nr] = 3; | ||
305 | break; | ||
281 | default: | 306 | default: |
282 | mutex_unlock(&data->update_lock); | 307 | mutex_unlock(&data->update_lock); |
283 | return -EINVAL; | 308 | return -EINVAL; |
@@ -315,7 +340,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute | |||
315 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 340 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
316 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 341 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
317 | int nr = attr->index; | 342 | int nr = attr->index; |
318 | long val = simple_strtol(buf, NULL, 10); | 343 | long val; |
344 | int err; | ||
345 | |||
346 | err = kstrtol(buf, 10, &val); | ||
347 | if (err) | ||
348 | return err; | ||
319 | 349 | ||
320 | if (val < 0 || val > 255) | 350 | if (val < 0 || val > 255) |
321 | return -EINVAL; | 351 | return -EINVAL; |
@@ -336,9 +366,14 @@ static ssize_t set_pwm_en(struct device *dev, struct device_attribute | |||
336 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 366 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
337 | struct smsc47m1_data *data = dev_get_drvdata(dev); | 367 | struct smsc47m1_data *data = dev_get_drvdata(dev); |
338 | int nr = attr->index; | 368 | int nr = attr->index; |
339 | long val = simple_strtol(buf, NULL, 10); | 369 | unsigned long val; |
340 | 370 | int err; | |
341 | if (val != 0 && val != 1) | 371 | |
372 | err = kstrtoul(buf, 10, &val); | ||
373 | if (err) | ||
374 | return err; | ||
375 | |||
376 | if (val > 1) | ||
342 | return -EINVAL; | 377 | return -EINVAL; |
343 | 378 | ||
344 | mutex_lock(&data->update_lock); | 379 | mutex_lock(&data->update_lock); |
@@ -519,8 +554,10 @@ static int __init smsc47m1_find(unsigned short *addr, | |||
519 | return -ENODEV; | 554 | return -ENODEV; |
520 | } | 555 | } |
521 | 556 | ||
522 | /* Enable only if address is set (needed at least on the | 557 | /* |
523 | * Compaq Presario S4000NX) */ | 558 | * Enable only if address is set (needed at least on the |
559 | * Compaq Presario S4000NX) | ||
560 | */ | ||
524 | sio_data->activate = superio_inb(SUPERIO_REG_ACT); | 561 | sio_data->activate = superio_inb(SUPERIO_REG_ACT); |
525 | if ((sio_data->activate & 0x01) == 0) { | 562 | if ((sio_data->activate & 0x01) == 0) { |
526 | pr_info("Enabling device\n"); | 563 | pr_info("Enabling device\n"); |
@@ -646,7 +683,7 @@ static int __init smsc47m1_probe(struct platform_device *pdev) | |||
646 | int err; | 683 | int err; |
647 | int fan1, fan2, fan3, pwm1, pwm2, pwm3; | 684 | int fan1, fan2, fan3, pwm1, pwm2, pwm3; |
648 | 685 | ||
649 | static const char *names[] = { | 686 | static const char * const names[] = { |
650 | "smsc47m1", | 687 | "smsc47m1", |
651 | "smsc47m2", | 688 | "smsc47m2", |
652 | }; | 689 | }; |
@@ -657,7 +694,8 @@ static int __init smsc47m1_probe(struct platform_device *pdev) | |||
657 | if (err < 0) | 694 | if (err < 0) |
658 | return err; | 695 | return err; |
659 | 696 | ||
660 | if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { | 697 | data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL); |
698 | if (!data) { | ||
661 | err = -ENOMEM; | 699 | err = -ENOMEM; |
662 | goto error_release; | 700 | goto error_release; |
663 | } | 701 | } |
@@ -668,8 +706,10 @@ static int __init smsc47m1_probe(struct platform_device *pdev) | |||
668 | mutex_init(&data->update_lock); | 706 | mutex_init(&data->update_lock); |
669 | platform_set_drvdata(pdev, data); | 707 | platform_set_drvdata(pdev, data); |
670 | 708 | ||
671 | /* If no function is properly configured, there's no point in | 709 | /* |
672 | actually registering the chip. */ | 710 | * If no function is properly configured, there's no point in |
711 | * actually registering the chip. | ||
712 | */ | ||
673 | pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) | 713 | pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) |
674 | == 0x04; | 714 | == 0x04; |
675 | pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) | 715 | pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) |
@@ -697,12 +737,14 @@ static int __init smsc47m1_probe(struct platform_device *pdev) | |||
697 | goto error_free; | 737 | goto error_free; |
698 | } | 738 | } |
699 | 739 | ||
700 | /* Some values (fan min, clock dividers, pwm registers) may be | 740 | /* |
701 | needed before any update is triggered, so we better read them | 741 | * Some values (fan min, clock dividers, pwm registers) may be |
702 | at least once here. We don't usually do it that way, but in | 742 | * needed before any update is triggered, so we better read them |
703 | this particular case, manually reading 5 registers out of 8 | 743 | * at least once here. We don't usually do it that way, but in |
704 | doesn't make much sense and we're better using the existing | 744 | * this particular case, manually reading 5 registers out of 8 |
705 | function. */ | 745 | * doesn't make much sense and we're better using the existing |
746 | * function. | ||
747 | */ | ||
706 | smsc47m1_update_device(dev, 1); | 748 | smsc47m1_update_device(dev, 1); |
707 | 749 | ||
708 | /* Register sysfs hooks */ | 750 | /* Register sysfs hooks */ |