diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 19:52:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 19:52:50 -0400 |
commit | 0c63e38a129e7b1f625c6112439a4efc87b1635c (patch) | |
tree | bde880587c6a1da9eee2d44d3036b56e0d557f07 | |
parent | 0798b1dbfbd9ff2a370c5968c5f0621ef0075fe0 (diff) | |
parent | b0b349a85d3df00a40a8bd398e4a151fd8e91bbe (diff) |
Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
hwmon: New driver for the SMSC EMC6W201
hwmon: (abituguru) Depend on DMI
hwmon: (it87) Use request_muxed_region
hwmon: (sch5627) Trigger Vbat measurements
hwmon: (sch5627) Add sch5627_send_cmd function
i8k: Integrate with the hwmon subsystem
hwmon: (max6650) Properly support the MAX6650
hwmon: (max6650) Drop device detection
Move ACPI power meter driver to hwmon
hwmon: (f71882fg) Add support for F71808A
hwmon: (f71882fg) Split has_beep in fan_has_beep and temp_has_beep
hwmon: (asc7621) Drop duplicate dependency
hwmon: (jc42) Change detection class
hwmon: Add driver for AMD family 15h processor power information
hwmon: (k10temp) Add support for Fam15h (Bulldozer)
hwmon: Use helper functions to set and get driver data
i8k: Avoid lahf in 64-bit code
29 files changed, 1305 insertions, 150 deletions
diff --git a/Documentation/hwmon/emc6w201 b/Documentation/hwmon/emc6w201 new file mode 100644 index 000000000000..32f355aaf56b --- /dev/null +++ b/Documentation/hwmon/emc6w201 | |||
@@ -0,0 +1,42 @@ | |||
1 | Kernel driver emc6w201 | ||
2 | ====================== | ||
3 | |||
4 | Supported chips: | ||
5 | * SMSC EMC6W201 | ||
6 | Prefix: 'emc6w201' | ||
7 | Addresses scanned: I2C 0x2c, 0x2d, 0x2e | ||
8 | Datasheet: Not public | ||
9 | |||
10 | Author: Jean Delvare <khali@linux-fr.org> | ||
11 | |||
12 | |||
13 | Description | ||
14 | ----------- | ||
15 | |||
16 | From the datasheet: | ||
17 | |||
18 | "The EMC6W201 is an environmental monitoring device with automatic fan | ||
19 | control capability and enhanced system acoustics for noise suppression. | ||
20 | This ACPI compliant device provides hardware monitoring for up to six | ||
21 | voltages (including its own VCC) and five external thermal sensors, | ||
22 | measures the speed of up to five fans, and controls the speed of | ||
23 | multiple DC fans using three Pulse Width Modulator (PWM) outputs. Note | ||
24 | that it is possible to control more than three fans by connecting two | ||
25 | fans to one PWM output. The EMC6W201 will be available in a 36-pin | ||
26 | QFN package." | ||
27 | |||
28 | The device is functionally close to the EMC6D100 series, but is | ||
29 | register-incompatible. | ||
30 | |||
31 | The driver currently only supports the monitoring of the voltages, | ||
32 | temperatures and fan speeds. Limits can be changed. Alarms are not | ||
33 | supported, and neither is fan speed control. | ||
34 | |||
35 | |||
36 | Known Systems With EMC6W201 | ||
37 | --------------------------- | ||
38 | |||
39 | The EMC6W201 is a rare device, only found on a few systems, made in | ||
40 | 2005 and 2006. Known systems with this device: | ||
41 | * Dell Precision 670 workstation | ||
42 | * Gigabyte 2CEWH mainboard | ||
diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index df02245d1419..84d2623810f3 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg | |||
@@ -6,6 +6,10 @@ Supported chips: | |||
6 | Prefix: 'f71808e' | 6 | Prefix: 'f71808e' |
7 | Addresses scanned: none, address read from Super I/O config space | 7 | Addresses scanned: none, address read from Super I/O config space |
8 | Datasheet: Not public | 8 | Datasheet: Not public |
9 | * Fintek F71808A | ||
10 | Prefix: 'f71808a' | ||
11 | Addresses scanned: none, address read from Super I/O config space | ||
12 | Datasheet: Not public | ||
9 | * Fintek F71858FG | 13 | * Fintek F71858FG |
10 | Prefix: 'f71858fg' | 14 | Prefix: 'f71858fg' |
11 | Addresses scanned: none, address read from Super I/O config space | 15 | Addresses scanned: none, address read from Super I/O config space |
diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power new file mode 100644 index 000000000000..a92918e0bd69 --- /dev/null +++ b/Documentation/hwmon/fam15h_power | |||
@@ -0,0 +1,37 @@ | |||
1 | Kernel driver fam15h_power | ||
2 | ========================== | ||
3 | |||
4 | Supported chips: | ||
5 | * AMD Family 15h Processors | ||
6 | |||
7 | Prefix: 'fam15h_power' | ||
8 | Addresses scanned: PCI space | ||
9 | Datasheets: | ||
10 | BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors | ||
11 | (not yet published) | ||
12 | |||
13 | Author: Andreas Herrmann <andreas.herrmann3@amd.com> | ||
14 | |||
15 | Description | ||
16 | ----------- | ||
17 | |||
18 | This driver permits reading of registers providing power information | ||
19 | of AMD Family 15h processors. | ||
20 | |||
21 | For AMD Family 15h processors the following power values can be | ||
22 | calculated using different processor northbridge function registers: | ||
23 | |||
24 | * BasePwrWatts: Specifies in watts the maximum amount of power | ||
25 | consumed by the processor for NB and logic external to the core. | ||
26 | * ProcessorPwrWatts: Specifies in watts the maximum amount of power | ||
27 | the processor can support. | ||
28 | * CurrPwrWatts: Specifies in watts the current amount of power being | ||
29 | consumed by the processor. | ||
30 | |||
31 | This driver provides ProcessorPwrWatts and CurrPwrWatts: | ||
32 | * power1_crit (ProcessorPwrWatts) | ||
33 | * power1_input (CurrPwrWatts) | ||
34 | |||
35 | On multi-node processors the calculated value is for the entire | ||
36 | package and not for a single node. Thus the driver creates sysfs | ||
37 | attributes only for internal node0 of a multi-node processor. | ||
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp index d2b56a4fd1f5..0393c89277c0 100644 --- a/Documentation/hwmon/k10temp +++ b/Documentation/hwmon/k10temp | |||
@@ -11,6 +11,7 @@ Supported chips: | |||
11 | Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra) | 11 | Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra) |
12 | * AMD Family 12h processors: "Llano" | 12 | * AMD Family 12h processors: "Llano" |
13 | * AMD Family 14h processors: "Brazos" (C/E/G-Series) | 13 | * AMD Family 14h processors: "Brazos" (C/E/G-Series) |
14 | * AMD Family 15h processors: "Bulldozer" | ||
14 | 15 | ||
15 | Prefix: 'k10temp' | 16 | Prefix: 'k10temp' |
16 | Addresses scanned: PCI space | 17 | Addresses scanned: PCI space |
@@ -40,7 +41,7 @@ Description | |||
40 | ----------- | 41 | ----------- |
41 | 42 | ||
42 | This driver permits reading of the internal temperature sensor of AMD | 43 | This driver permits reading of the internal temperature sensor of AMD |
43 | Family 10h/11h/12h/14h processors. | 44 | Family 10h/11h/12h/14h/15h processors. |
44 | 45 | ||
45 | All these processors have a sensor, but on those for Socket F or AM2+, | 46 | All these processors have a sensor, but on those for Socket F or AM2+, |
46 | the sensor may return inconsistent values (erratum 319). The driver | 47 | the sensor may return inconsistent values (erratum 319). The driver |
diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650 index c565650fcfc6..58d9644a2bde 100644 --- a/Documentation/hwmon/max6650 +++ b/Documentation/hwmon/max6650 | |||
@@ -2,9 +2,13 @@ Kernel driver max6650 | |||
2 | ===================== | 2 | ===================== |
3 | 3 | ||
4 | Supported chips: | 4 | Supported chips: |
5 | * Maxim 6650 / 6651 | 5 | * Maxim MAX6650 |
6 | Prefix: 'max6650' | 6 | Prefix: 'max6650' |
7 | Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b | 7 | Addresses scanned: none |
8 | Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf | ||
9 | * Maxim MAX6651 | ||
10 | Prefix: 'max6651' | ||
11 | Addresses scanned: none | ||
8 | Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf | 12 | Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf |
9 | 13 | ||
10 | Authors: | 14 | Authors: |
@@ -15,10 +19,10 @@ Authors: | |||
15 | Description | 19 | Description |
16 | ----------- | 20 | ----------- |
17 | 21 | ||
18 | This driver implements support for the Maxim 6650/6651 | 22 | This driver implements support for the Maxim MAX6650 and MAX6651. |
19 | 23 | ||
20 | The 2 devices are very similar, but the Maxim 6550 has a reduced feature | 24 | The 2 devices are very similar, but the MAX6550 has a reduced feature |
21 | set, e.g. only one fan-input, instead of 4 for the 6651. | 25 | set, e.g. only one fan-input, instead of 4 for the MAX6651. |
22 | 26 | ||
23 | The driver is not able to distinguish between the 2 devices. | 27 | The driver is not able to distinguish between the 2 devices. |
24 | 28 | ||
@@ -36,6 +40,13 @@ fan1_div rw sets the speed range the inputs can handle. Legal | |||
36 | values are 1, 2, 4, and 8. Use lower values for | 40 | values are 1, 2, 4, and 8. Use lower values for |
37 | faster fans. | 41 | faster fans. |
38 | 42 | ||
43 | Usage notes | ||
44 | ----------- | ||
45 | |||
46 | This driver does not auto-detect devices. You will have to instantiate the | ||
47 | devices explicitly. Please see Documentation/i2c/instantiating-devices for | ||
48 | details. | ||
49 | |||
39 | Module parameters | 50 | Module parameters |
40 | ----------------- | 51 | ----------------- |
41 | 52 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index f5b62956be83..a26c9ee7703d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -483,6 +483,13 @@ F: drivers/tty/serial/altera_jtaguart.c | |||
483 | F: include/linux/altera_uart.h | 483 | F: include/linux/altera_uart.h |
484 | F: include/linux/altera_jtaguart.h | 484 | F: include/linux/altera_jtaguart.h |
485 | 485 | ||
486 | AMD FAM15H PROCESSOR POWER MONITORING DRIVER | ||
487 | M: Andreas Herrmann <andreas.herrmann3@amd.com> | ||
488 | L: lm-sensors@lm-sensors.org | ||
489 | S: Maintained | ||
490 | F: Documentation/hwmon/fam15h_power | ||
491 | F: drivers/hwmon/fam15h_power.c | ||
492 | |||
486 | AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER | 493 | AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER |
487 | M: Thomas Dahlmann <dahlmann.thomas@arcor.de> | 494 | M: Thomas Dahlmann <dahlmann.thomas@arcor.de> |
488 | L: linux-geode@lists.infradead.org (moderated for non-subscribers) | 495 | L: linux-geode@lists.infradead.org (moderated for non-subscribers) |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fa2cc8c5d01c..483775f42d2a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -915,6 +915,7 @@ config TOSHIBA | |||
915 | 915 | ||
916 | config I8K | 916 | config I8K |
917 | tristate "Dell laptop support" | 917 | tristate "Dell laptop support" |
918 | select HWMON | ||
918 | ---help--- | 919 | ---help--- |
919 | This adds a driver to safely access the System Management Mode | 920 | This adds a driver to safely access the System Management Mode |
920 | of the CPU on the Dell Inspiron 8000. The System Management Mode | 921 | of the CPU on the Dell Inspiron 8000. The System Management Mode |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 3a17ca5fff6f..bc2218db5ba9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -73,17 +73,6 @@ config ACPI_PROCFS_POWER | |||
73 | 73 | ||
74 | Say N to delete power /proc/acpi/ directories that have moved to /sys/ | 74 | Say N to delete power /proc/acpi/ directories that have moved to /sys/ |
75 | 75 | ||
76 | config ACPI_POWER_METER | ||
77 | tristate "ACPI 4.0 power meter" | ||
78 | depends on HWMON | ||
79 | help | ||
80 | This driver exposes ACPI 4.0 power meters as hardware monitoring | ||
81 | devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware | ||
82 | and a power meter. | ||
83 | |||
84 | To compile this driver as a module, choose M here: | ||
85 | the module will be called power-meter. | ||
86 | |||
87 | config ACPI_EC_DEBUGFS | 76 | config ACPI_EC_DEBUGFS |
88 | tristate "EC read/write access through /sys/kernel/debug/ec" | 77 | tristate "EC read/write access through /sys/kernel/debug/ec" |
89 | default n | 78 | default n |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d113fa5100b2..b66fbb2fc85f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -59,7 +59,6 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o | |||
59 | obj-$(CONFIG_ACPI_BATTERY) += battery.o | 59 | obj-$(CONFIG_ACPI_BATTERY) += battery.o |
60 | obj-$(CONFIG_ACPI_SBS) += sbshc.o | 60 | obj-$(CONFIG_ACPI_SBS) += sbshc.o |
61 | obj-$(CONFIG_ACPI_SBS) += sbs.o | 61 | obj-$(CONFIG_ACPI_SBS) += sbs.o |
62 | obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o | ||
63 | obj-$(CONFIG_ACPI_HED) += hed.o | 62 | obj-$(CONFIG_ACPI_HED) += hed.o |
64 | obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o | 63 | obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o |
65 | 64 | ||
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index d72433f2d310..6e40072fbf67 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c | |||
@@ -5,6 +5,9 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> | 6 | * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> |
7 | * | 7 | * |
8 | * Hwmon integration: | ||
9 | * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org> | ||
10 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2, or (at your option) any | 13 | * Free Software Foundation; either version 2, or (at your option) any |
@@ -24,6 +27,8 @@ | |||
24 | #include <linux/dmi.h> | 27 | #include <linux/dmi.h> |
25 | #include <linux/capability.h> | 28 | #include <linux/capability.h> |
26 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
30 | #include <linux/hwmon.h> | ||
31 | #include <linux/hwmon-sysfs.h> | ||
27 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
28 | #include <asm/io.h> | 33 | #include <asm/io.h> |
29 | 34 | ||
@@ -58,6 +63,7 @@ | |||
58 | 63 | ||
59 | static DEFINE_MUTEX(i8k_mutex); | 64 | static DEFINE_MUTEX(i8k_mutex); |
60 | static char bios_version[4]; | 65 | static char bios_version[4]; |
66 | static struct device *i8k_hwmon_dev; | ||
61 | 67 | ||
62 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); | 68 | MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); |
63 | MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); | 69 | MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); |
@@ -139,8 +145,8 @@ static int i8k_smm(struct smm_regs *regs) | |||
139 | "movl %%edi,20(%%rax)\n\t" | 145 | "movl %%edi,20(%%rax)\n\t" |
140 | "popq %%rdx\n\t" | 146 | "popq %%rdx\n\t" |
141 | "movl %%edx,0(%%rax)\n\t" | 147 | "movl %%edx,0(%%rax)\n\t" |
142 | "lahf\n\t" | 148 | "pushfq\n\t" |
143 | "shrl $8,%%eax\n\t" | 149 | "popq %%rax\n\t" |
144 | "andl $1,%%eax\n" | 150 | "andl $1,%%eax\n" |
145 | :"=a"(rc) | 151 | :"=a"(rc) |
146 | : "a"(regs) | 152 | : "a"(regs) |
@@ -455,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file) | |||
455 | return single_open(file, i8k_proc_show, NULL); | 461 | return single_open(file, i8k_proc_show, NULL); |
456 | } | 462 | } |
457 | 463 | ||
464 | |||
465 | /* | ||
466 | * Hwmon interface | ||
467 | */ | ||
468 | |||
469 | static ssize_t i8k_hwmon_show_temp(struct device *dev, | ||
470 | struct device_attribute *devattr, | ||
471 | char *buf) | ||
472 | { | ||
473 | int cpu_temp; | ||
474 | |||
475 | cpu_temp = i8k_get_temp(0); | ||
476 | if (cpu_temp < 0) | ||
477 | return cpu_temp; | ||
478 | return sprintf(buf, "%d\n", cpu_temp * 1000); | ||
479 | } | ||
480 | |||
481 | static ssize_t i8k_hwmon_show_fan(struct device *dev, | ||
482 | struct device_attribute *devattr, | ||
483 | char *buf) | ||
484 | { | ||
485 | int index = to_sensor_dev_attr(devattr)->index; | ||
486 | int fan_speed; | ||
487 | |||
488 | fan_speed = i8k_get_fan_speed(index); | ||
489 | if (fan_speed < 0) | ||
490 | return fan_speed; | ||
491 | return sprintf(buf, "%d\n", fan_speed); | ||
492 | } | ||
493 | |||
494 | static ssize_t i8k_hwmon_show_label(struct device *dev, | ||
495 | struct device_attribute *devattr, | ||
496 | char *buf) | ||
497 | { | ||
498 | static const char *labels[4] = { | ||
499 | "i8k", | ||
500 | "CPU", | ||
501 | "Left Fan", | ||
502 | "Right Fan", | ||
503 | }; | ||
504 | int index = to_sensor_dev_attr(devattr)->index; | ||
505 | |||
506 | return sprintf(buf, "%s\n", labels[index]); | ||
507 | } | ||
508 | |||
509 | static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL); | ||
510 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, | ||
511 | I8K_FAN_LEFT); | ||
512 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, | ||
513 | I8K_FAN_RIGHT); | ||
514 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0); | ||
515 | static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1); | ||
516 | static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2); | ||
517 | static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3); | ||
518 | |||
519 | static void i8k_hwmon_remove_files(struct device *dev) | ||
520 | { | ||
521 | device_remove_file(dev, &dev_attr_temp1_input); | ||
522 | device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr); | ||
523 | device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr); | ||
524 | device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr); | ||
525 | device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr); | ||
526 | device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr); | ||
527 | device_remove_file(dev, &sensor_dev_attr_name.dev_attr); | ||
528 | } | ||
529 | |||
530 | static int __init i8k_init_hwmon(void) | ||
531 | { | ||
532 | int err; | ||
533 | |||
534 | i8k_hwmon_dev = hwmon_device_register(NULL); | ||
535 | if (IS_ERR(i8k_hwmon_dev)) { | ||
536 | err = PTR_ERR(i8k_hwmon_dev); | ||
537 | i8k_hwmon_dev = NULL; | ||
538 | printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err); | ||
539 | return err; | ||
540 | } | ||
541 | |||
542 | /* Required name attribute */ | ||
543 | err = device_create_file(i8k_hwmon_dev, | ||
544 | &sensor_dev_attr_name.dev_attr); | ||
545 | if (err) | ||
546 | goto exit_unregister; | ||
547 | |||
548 | /* CPU temperature attributes, if temperature reading is OK */ | ||
549 | err = i8k_get_temp(0); | ||
550 | if (err < 0) { | ||
551 | dev_dbg(i8k_hwmon_dev, | ||
552 | "Not creating temperature attributes (%d)\n", err); | ||
553 | } else { | ||
554 | err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input); | ||
555 | if (err) | ||
556 | goto exit_remove_files; | ||
557 | err = device_create_file(i8k_hwmon_dev, | ||
558 | &sensor_dev_attr_temp1_label.dev_attr); | ||
559 | if (err) | ||
560 | goto exit_remove_files; | ||
561 | } | ||
562 | |||
563 | /* Left fan attributes, if left fan is present */ | ||
564 | err = i8k_get_fan_status(I8K_FAN_LEFT); | ||
565 | if (err < 0) { | ||
566 | dev_dbg(i8k_hwmon_dev, | ||
567 | "Not creating %s fan attributes (%d)\n", "left", err); | ||
568 | } else { | ||
569 | err = device_create_file(i8k_hwmon_dev, | ||
570 | &sensor_dev_attr_fan1_input.dev_attr); | ||
571 | if (err) | ||
572 | goto exit_remove_files; | ||
573 | err = device_create_file(i8k_hwmon_dev, | ||
574 | &sensor_dev_attr_fan1_label.dev_attr); | ||
575 | if (err) | ||
576 | goto exit_remove_files; | ||
577 | } | ||
578 | |||
579 | /* Right fan attributes, if right fan is present */ | ||
580 | err = i8k_get_fan_status(I8K_FAN_RIGHT); | ||
581 | if (err < 0) { | ||
582 | dev_dbg(i8k_hwmon_dev, | ||
583 | "Not creating %s fan attributes (%d)\n", "right", err); | ||
584 | } else { | ||
585 | err = device_create_file(i8k_hwmon_dev, | ||
586 | &sensor_dev_attr_fan2_input.dev_attr); | ||
587 | if (err) | ||
588 | goto exit_remove_files; | ||
589 | err = device_create_file(i8k_hwmon_dev, | ||
590 | &sensor_dev_attr_fan2_label.dev_attr); | ||
591 | if (err) | ||
592 | goto exit_remove_files; | ||
593 | } | ||
594 | |||
595 | return 0; | ||
596 | |||
597 | exit_remove_files: | ||
598 | i8k_hwmon_remove_files(i8k_hwmon_dev); | ||
599 | exit_unregister: | ||
600 | hwmon_device_unregister(i8k_hwmon_dev); | ||
601 | return err; | ||
602 | } | ||
603 | |||
604 | static void __exit i8k_exit_hwmon(void) | ||
605 | { | ||
606 | i8k_hwmon_remove_files(i8k_hwmon_dev); | ||
607 | hwmon_device_unregister(i8k_hwmon_dev); | ||
608 | } | ||
609 | |||
458 | static struct dmi_system_id __initdata i8k_dmi_table[] = { | 610 | static struct dmi_system_id __initdata i8k_dmi_table[] = { |
459 | { | 611 | { |
460 | .ident = "Dell Inspiron", | 612 | .ident = "Dell Inspiron", |
@@ -580,6 +732,7 @@ static int __init i8k_probe(void) | |||
580 | static int __init i8k_init(void) | 732 | static int __init i8k_init(void) |
581 | { | 733 | { |
582 | struct proc_dir_entry *proc_i8k; | 734 | struct proc_dir_entry *proc_i8k; |
735 | int err; | ||
583 | 736 | ||
584 | /* Are we running on an supported laptop? */ | 737 | /* Are we running on an supported laptop? */ |
585 | if (i8k_probe()) | 738 | if (i8k_probe()) |
@@ -590,15 +743,24 @@ static int __init i8k_init(void) | |||
590 | if (!proc_i8k) | 743 | if (!proc_i8k) |
591 | return -ENOENT; | 744 | return -ENOENT; |
592 | 745 | ||
746 | err = i8k_init_hwmon(); | ||
747 | if (err) | ||
748 | goto exit_remove_proc; | ||
749 | |||
593 | printk(KERN_INFO | 750 | printk(KERN_INFO |
594 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", | 751 | "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", |
595 | I8K_VERSION); | 752 | I8K_VERSION); |
596 | 753 | ||
597 | return 0; | 754 | return 0; |
755 | |||
756 | exit_remove_proc: | ||
757 | remove_proc_entry("i8k", NULL); | ||
758 | return err; | ||
598 | } | 759 | } |
599 | 760 | ||
600 | static void __exit i8k_exit(void) | 761 | static void __exit i8k_exit(void) |
601 | { | 762 | { |
763 | i8k_exit_hwmon(); | ||
602 | remove_proc_entry("i8k", NULL); | 764 | remove_proc_entry("i8k", NULL); |
603 | } | 765 | } |
604 | 766 | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 43221beb9e97..16db83c83c8b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -41,7 +41,7 @@ comment "Native drivers" | |||
41 | 41 | ||
42 | config SENSORS_ABITUGURU | 42 | config SENSORS_ABITUGURU |
43 | tristate "Abit uGuru (rev 1 & 2)" | 43 | tristate "Abit uGuru (rev 1 & 2)" |
44 | depends on X86 && EXPERIMENTAL | 44 | depends on X86 && DMI && EXPERIMENTAL |
45 | help | 45 | help |
46 | If you say yes here you get support for the sensor part of the first | 46 | If you say yes here you get support for the sensor part of the first |
47 | and second revision of the Abit uGuru chip. The voltage and frequency | 47 | and second revision of the Abit uGuru chip. The voltage and frequency |
@@ -56,7 +56,7 @@ config SENSORS_ABITUGURU | |||
56 | 56 | ||
57 | config SENSORS_ABITUGURU3 | 57 | config SENSORS_ABITUGURU3 |
58 | tristate "Abit uGuru (rev 3)" | 58 | tristate "Abit uGuru (rev 3)" |
59 | depends on X86 && EXPERIMENTAL | 59 | depends on X86 && DMI && EXPERIMENTAL |
60 | help | 60 | help |
61 | If you say yes here you get support for the sensor part of the | 61 | If you say yes here you get support for the sensor part of the |
62 | third revision of the Abit uGuru chip. Only reading the sensors | 62 | third revision of the Abit uGuru chip. Only reading the sensors |
@@ -213,7 +213,7 @@ config SENSORS_ADT7475 | |||
213 | 213 | ||
214 | config SENSORS_ASC7621 | 214 | config SENSORS_ASC7621 |
215 | tristate "Andigilog aSC7621" | 215 | tristate "Andigilog aSC7621" |
216 | depends on HWMON && I2C | 216 | depends on I2C |
217 | help | 217 | help |
218 | If you say yes here you get support for the aSC7621 | 218 | If you say yes here you get support for the aSC7621 |
219 | family of SMBus sensors chip found on most Intel X38, X48, X58, | 219 | family of SMBus sensors chip found on most Intel X38, X48, X58, |
@@ -237,17 +237,27 @@ config SENSORS_K8TEMP | |||
237 | will be called k8temp. | 237 | will be called k8temp. |
238 | 238 | ||
239 | config SENSORS_K10TEMP | 239 | config SENSORS_K10TEMP |
240 | tristate "AMD Family 10h/11h/12h/14h temperature sensor" | 240 | tristate "AMD Family 10h+ temperature sensor" |
241 | depends on X86 && PCI | 241 | depends on X86 && PCI |
242 | help | 242 | help |
243 | If you say yes here you get support for the temperature | 243 | If you say yes here you get support for the temperature |
244 | sensor(s) inside your CPU. Supported are later revisions of | 244 | sensor(s) inside your CPU. Supported are later revisions of |
245 | the AMD Family 10h and all revisions of the AMD Family 11h, | 245 | the AMD Family 10h and all revisions of the AMD Family 11h, |
246 | 12h (Llano), and 14h (Brazos) microarchitectures. | 246 | 12h (Llano), 14h (Brazos) and 15h (Bulldozer) microarchitectures. |
247 | 247 | ||
248 | This driver can also be built as a module. If so, the module | 248 | This driver can also be built as a module. If so, the module |
249 | will be called k10temp. | 249 | will be called k10temp. |
250 | 250 | ||
251 | config SENSORS_FAM15H_POWER | ||
252 | tristate "AMD Family 15h processor power" | ||
253 | depends on X86 && PCI | ||
254 | help | ||
255 | If you say yes here you get support for processor power | ||
256 | information of your AMD family 15h CPU. | ||
257 | |||
258 | This driver can also be built as a module. If so, the module | ||
259 | will be called fam15h_power. | ||
260 | |||
251 | config SENSORS_ASB100 | 261 | config SENSORS_ASB100 |
252 | tristate "Asus ASB100 Bach" | 262 | tristate "Asus ASB100 Bach" |
253 | depends on X86 && I2C && EXPERIMENTAL | 263 | depends on X86 && I2C && EXPERIMENTAL |
@@ -319,7 +329,7 @@ config SENSORS_F71882FG | |||
319 | If you say yes here you get support for hardware monitoring | 329 | If you say yes here you get support for hardware monitoring |
320 | features of many Fintek Super-I/O (LPC) chips. The currently | 330 | features of many Fintek Super-I/O (LPC) chips. The currently |
321 | supported chips are: | 331 | supported chips are: |
322 | F71808E | 332 | F71808E/A |
323 | F71858FG | 333 | F71858FG |
324 | F71862FG | 334 | F71862FG |
325 | F71863FG | 335 | F71863FG |
@@ -978,6 +988,16 @@ config SENSORS_EMC2103 | |||
978 | This driver can also be built as a module. If so, the module | 988 | This driver can also be built as a module. If so, the module |
979 | will be called emc2103. | 989 | will be called emc2103. |
980 | 990 | ||
991 | config SENSORS_EMC6W201 | ||
992 | tristate "SMSC EMC6W201" | ||
993 | depends on I2C | ||
994 | help | ||
995 | If you say yes here you get support for the SMSC EMC6W201 | ||
996 | hardware monitoring chip. | ||
997 | |||
998 | This driver can also be built as a module. If so, the module | ||
999 | will be called emc6w201. | ||
1000 | |||
981 | config SENSORS_SMSC47M1 | 1001 | config SENSORS_SMSC47M1 |
982 | tristate "SMSC LPC47M10x and compatibles" | 1002 | tristate "SMSC LPC47M10x and compatibles" |
983 | help | 1003 | help |
@@ -1341,6 +1361,16 @@ if ACPI | |||
1341 | 1361 | ||
1342 | comment "ACPI drivers" | 1362 | comment "ACPI drivers" |
1343 | 1363 | ||
1364 | config SENSORS_ACPI_POWER | ||
1365 | tristate "ACPI 4.0 power meter" | ||
1366 | help | ||
1367 | This driver exposes ACPI 4.0 power meters as hardware monitoring | ||
1368 | devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware | ||
1369 | and a power meter. | ||
1370 | |||
1371 | To compile this driver as a module, choose M here: | ||
1372 | the module will be called acpi_power_meter. | ||
1373 | |||
1344 | config SENSORS_ATK0110 | 1374 | config SENSORS_ATK0110 |
1345 | tristate "ASUS ATK0110" | 1375 | tristate "ASUS ATK0110" |
1346 | depends on X86 && EXPERIMENTAL | 1376 | depends on X86 && EXPERIMENTAL |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 28e8d52f6379..28061cfa0cdb 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_HWMON) += hwmon.o | |||
6 | obj-$(CONFIG_HWMON_VID) += hwmon-vid.o | 6 | obj-$(CONFIG_HWMON_VID) += hwmon-vid.o |
7 | 7 | ||
8 | # APCI drivers | 8 | # APCI drivers |
9 | obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o | ||
9 | obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o | 10 | obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o |
10 | 11 | ||
11 | # Native drivers | 12 | # Native drivers |
@@ -45,9 +46,11 @@ obj-$(CONFIG_SENSORS_DS620) += ds620.o | |||
45 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o | 46 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o |
46 | obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o | 47 | obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o |
47 | obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o | 48 | obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o |
49 | obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o | ||
48 | obj-$(CONFIG_SENSORS_F71805F) += f71805f.o | 50 | obj-$(CONFIG_SENSORS_F71805F) += f71805f.o |
49 | obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o | 51 | obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o |
50 | obj-$(CONFIG_SENSORS_F75375S) += f75375s.o | 52 | obj-$(CONFIG_SENSORS_F75375S) += f75375s.o |
53 | obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o | ||
51 | obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o | 54 | obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o |
52 | obj-$(CONFIG_SENSORS_G760A) += g760a.o | 55 | obj-$(CONFIG_SENSORS_G760A) += g760a.o |
53 | obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o | 56 | obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o |
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index e7d4c4687f02..65a35cf5b3c5 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c | |||
@@ -1448,15 +1448,12 @@ static int __init abituguru_init(void) | |||
1448 | { | 1448 | { |
1449 | int address, err; | 1449 | int address, err; |
1450 | struct resource res = { .flags = IORESOURCE_IO }; | 1450 | struct resource res = { .flags = IORESOURCE_IO }; |
1451 | |||
1452 | #ifdef CONFIG_DMI | ||
1453 | const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); | 1451 | const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); |
1454 | 1452 | ||
1455 | /* safety check, refuse to load on non Abit motherboards */ | 1453 | /* safety check, refuse to load on non Abit motherboards */ |
1456 | if (!force && (!board_vendor || | 1454 | if (!force && (!board_vendor || |
1457 | strcmp(board_vendor, "http://www.abit.com.tw/"))) | 1455 | strcmp(board_vendor, "http://www.abit.com.tw/"))) |
1458 | return -ENODEV; | 1456 | return -ENODEV; |
1459 | #endif | ||
1460 | 1457 | ||
1461 | address = abituguru_detect(); | 1458 | address = abituguru_detect(); |
1462 | if (address < 0) | 1459 | if (address < 0) |
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index e89d572e3320..d30855a75786 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c | |||
@@ -1119,8 +1119,6 @@ static struct platform_driver abituguru3_driver = { | |||
1119 | .resume = abituguru3_resume | 1119 | .resume = abituguru3_resume |
1120 | }; | 1120 | }; |
1121 | 1121 | ||
1122 | #ifdef CONFIG_DMI | ||
1123 | |||
1124 | static int __init abituguru3_dmi_detect(void) | 1122 | static int __init abituguru3_dmi_detect(void) |
1125 | { | 1123 | { |
1126 | const char *board_vendor, *board_name; | 1124 | const char *board_vendor, *board_name; |
@@ -1159,15 +1157,6 @@ static int __init abituguru3_dmi_detect(void) | |||
1159 | return 1; | 1157 | return 1; |
1160 | } | 1158 | } |
1161 | 1159 | ||
1162 | #else /* !CONFIG_DMI */ | ||
1163 | |||
1164 | static inline int abituguru3_dmi_detect(void) | ||
1165 | { | ||
1166 | return 1; | ||
1167 | } | ||
1168 | |||
1169 | #endif /* CONFIG_DMI */ | ||
1170 | |||
1171 | /* FIXME: Manual detection should die eventually; we need to collect stable | 1160 | /* FIXME: Manual detection should die eventually; we need to collect stable |
1172 | * DMI model names first before we can rely entirely on CONFIG_DMI. | 1161 | * DMI model names first before we can rely entirely on CONFIG_DMI. |
1173 | */ | 1162 | */ |
@@ -1216,10 +1205,8 @@ static int __init abituguru3_init(void) | |||
1216 | if (err) | 1205 | if (err) |
1217 | return err; | 1206 | return err; |
1218 | 1207 | ||
1219 | #ifdef CONFIG_DMI | ||
1220 | pr_warn("this motherboard was not detected using DMI. " | 1208 | pr_warn("this motherboard was not detected using DMI. " |
1221 | "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n"); | 1209 | "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n"); |
1222 | #endif | ||
1223 | } | 1210 | } |
1224 | 1211 | ||
1225 | err = platform_driver_register(&abituguru3_driver); | 1212 | err = platform_driver_register(&abituguru3_driver); |
diff --git a/drivers/acpi/power_meter.c b/drivers/hwmon/acpi_power_meter.c index 66f67293341e..66f67293341e 100644 --- a/drivers/acpi/power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c | |||
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index fbdc7655303b..b2cacbe707a8 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c | |||
@@ -62,7 +62,7 @@ static ssize_t adcxx_read(struct device *dev, | |||
62 | { | 62 | { |
63 | struct spi_device *spi = to_spi_device(dev); | 63 | struct spi_device *spi = to_spi_device(dev); |
64 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | 64 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
65 | struct adcxx *adc = dev_get_drvdata(&spi->dev); | 65 | struct adcxx *adc = spi_get_drvdata(spi); |
66 | u8 tx_buf[2]; | 66 | u8 tx_buf[2]; |
67 | u8 rx_buf[2]; | 67 | u8 rx_buf[2]; |
68 | int status; | 68 | int status; |
@@ -105,7 +105,7 @@ static ssize_t adcxx_show_max(struct device *dev, | |||
105 | struct device_attribute *devattr, char *buf) | 105 | struct device_attribute *devattr, char *buf) |
106 | { | 106 | { |
107 | struct spi_device *spi = to_spi_device(dev); | 107 | struct spi_device *spi = to_spi_device(dev); |
108 | struct adcxx *adc = dev_get_drvdata(&spi->dev); | 108 | struct adcxx *adc = spi_get_drvdata(spi); |
109 | u32 reference; | 109 | u32 reference; |
110 | 110 | ||
111 | if (mutex_lock_interruptible(&adc->lock)) | 111 | if (mutex_lock_interruptible(&adc->lock)) |
@@ -122,7 +122,7 @@ static ssize_t adcxx_set_max(struct device *dev, | |||
122 | struct device_attribute *devattr, const char *buf, size_t count) | 122 | struct device_attribute *devattr, const char *buf, size_t count) |
123 | { | 123 | { |
124 | struct spi_device *spi = to_spi_device(dev); | 124 | struct spi_device *spi = to_spi_device(dev); |
125 | struct adcxx *adc = dev_get_drvdata(&spi->dev); | 125 | struct adcxx *adc = spi_get_drvdata(spi); |
126 | unsigned long value; | 126 | unsigned long value; |
127 | 127 | ||
128 | if (strict_strtoul(buf, 10, &value)) | 128 | if (strict_strtoul(buf, 10, &value)) |
@@ -142,7 +142,7 @@ static ssize_t adcxx_show_name(struct device *dev, struct device_attribute | |||
142 | *devattr, char *buf) | 142 | *devattr, char *buf) |
143 | { | 143 | { |
144 | struct spi_device *spi = to_spi_device(dev); | 144 | struct spi_device *spi = to_spi_device(dev); |
145 | struct adcxx *adc = dev_get_drvdata(&spi->dev); | 145 | struct adcxx *adc = spi_get_drvdata(spi); |
146 | 146 | ||
147 | return sprintf(buf, "adcxx%ds\n", adc->channels); | 147 | return sprintf(buf, "adcxx%ds\n", adc->channels); |
148 | } | 148 | } |
@@ -182,7 +182,7 @@ static int __devinit adcxx_probe(struct spi_device *spi) | |||
182 | 182 | ||
183 | mutex_lock(&adc->lock); | 183 | mutex_lock(&adc->lock); |
184 | 184 | ||
185 | dev_set_drvdata(&spi->dev, adc); | 185 | spi_set_drvdata(spi, adc); |
186 | 186 | ||
187 | for (i = 0; i < 3 + adc->channels; i++) { | 187 | for (i = 0; i < 3 + adc->channels; i++) { |
188 | status = device_create_file(&spi->dev, &ad_input[i].dev_attr); | 188 | status = device_create_file(&spi->dev, &ad_input[i].dev_attr); |
@@ -206,7 +206,7 @@ out_err: | |||
206 | for (i--; i >= 0; i--) | 206 | for (i--; i >= 0; i--) |
207 | device_remove_file(&spi->dev, &ad_input[i].dev_attr); | 207 | device_remove_file(&spi->dev, &ad_input[i].dev_attr); |
208 | 208 | ||
209 | dev_set_drvdata(&spi->dev, NULL); | 209 | spi_set_drvdata(spi, NULL); |
210 | mutex_unlock(&adc->lock); | 210 | mutex_unlock(&adc->lock); |
211 | kfree(adc); | 211 | kfree(adc); |
212 | return status; | 212 | return status; |
@@ -214,7 +214,7 @@ out_err: | |||
214 | 214 | ||
215 | static int __devexit adcxx_remove(struct spi_device *spi) | 215 | static int __devexit adcxx_remove(struct spi_device *spi) |
216 | { | 216 | { |
217 | struct adcxx *adc = dev_get_drvdata(&spi->dev); | 217 | struct adcxx *adc = spi_get_drvdata(spi); |
218 | int i; | 218 | int i; |
219 | 219 | ||
220 | mutex_lock(&adc->lock); | 220 | mutex_lock(&adc->lock); |
@@ -222,7 +222,7 @@ static int __devexit adcxx_remove(struct spi_device *spi) | |||
222 | for (i = 0; i < 3 + adc->channels; i++) | 222 | for (i = 0; i < 3 + adc->channels; i++) |
223 | device_remove_file(&spi->dev, &ad_input[i].dev_attr); | 223 | device_remove_file(&spi->dev, &ad_input[i].dev_attr); |
224 | 224 | ||
225 | dev_set_drvdata(&spi->dev, NULL); | 225 | spi_set_drvdata(spi, NULL); |
226 | mutex_unlock(&adc->lock); | 226 | mutex_unlock(&adc->lock); |
227 | kfree(adc); | 227 | kfree(adc); |
228 | 228 | ||
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c new file mode 100644 index 000000000000..e0ef32378ac6 --- /dev/null +++ b/drivers/hwmon/emc6w201.c | |||
@@ -0,0 +1,539 @@ | |||
1 | /* | ||
2 | * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201 | ||
3 | * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/hwmon.h> | ||
27 | #include <linux/hwmon-sysfs.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/mutex.h> | ||
30 | |||
31 | /* | ||
32 | * Addresses to scan | ||
33 | */ | ||
34 | |||
35 | static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; | ||
36 | |||
37 | /* | ||
38 | * The EMC6W201 registers | ||
39 | */ | ||
40 | |||
41 | #define EMC6W201_REG_IN(nr) (0x20 + (nr)) | ||
42 | #define EMC6W201_REG_TEMP(nr) (0x26 + (nr)) | ||
43 | #define EMC6W201_REG_FAN(nr) (0x2C + (nr) * 2) | ||
44 | #define EMC6W201_REG_COMPANY 0x3E | ||
45 | #define EMC6W201_REG_VERSTEP 0x3F | ||
46 | #define EMC6W201_REG_CONFIG 0x40 | ||
47 | #define EMC6W201_REG_IN_LOW(nr) (0x4A + (nr) * 2) | ||
48 | #define EMC6W201_REG_IN_HIGH(nr) (0x4B + (nr) * 2) | ||
49 | #define EMC6W201_REG_TEMP_LOW(nr) (0x56 + (nr) * 2) | ||
50 | #define EMC6W201_REG_TEMP_HIGH(nr) (0x57 + (nr) * 2) | ||
51 | #define EMC6W201_REG_FAN_MIN(nr) (0x62 + (nr) * 2) | ||
52 | |||
53 | enum { input, min, max } subfeature; | ||
54 | |||
55 | /* | ||
56 | * Per-device data | ||
57 | */ | ||
58 | |||
59 | struct emc6w201_data { | ||
60 | struct device *hwmon_dev; | ||
61 | struct mutex update_lock; | ||
62 | char valid; /* zero until following fields are valid */ | ||
63 | unsigned long last_updated; /* in jiffies */ | ||
64 | |||
65 | /* registers values */ | ||
66 | u8 in[3][6]; | ||
67 | s8 temp[3][6]; | ||
68 | u16 fan[2][5]; | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * Combine LSB and MSB registers in a single value | ||
73 | * Locking: must be called with data->update_lock held | ||
74 | */ | ||
75 | static u16 emc6w201_read16(struct i2c_client *client, u8 reg) | ||
76 | { | ||
77 | int lsb, msb; | ||
78 | |||
79 | lsb = i2c_smbus_read_byte_data(client, reg); | ||
80 | msb = i2c_smbus_read_byte_data(client, reg + 1); | ||
81 | if (lsb < 0 || msb < 0) { | ||
82 | dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg); | ||
83 | return 0xFFFF; /* Arbitrary value */ | ||
84 | } | ||
85 | |||
86 | return (msb << 8) | lsb; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Write 16-bit value to LSB and MSB registers | ||
91 | * Locking: must be called with data->update_lock held | ||
92 | */ | ||
93 | static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val) | ||
94 | { | ||
95 | int err; | ||
96 | |||
97 | err = i2c_smbus_write_byte_data(client, reg, val & 0xff); | ||
98 | if (!err) | ||
99 | err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8); | ||
100 | if (err < 0) | ||
101 | dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg); | ||
102 | |||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static struct emc6w201_data *emc6w201_update_device(struct device *dev) | ||
107 | { | ||
108 | struct i2c_client *client = to_i2c_client(dev); | ||
109 | struct emc6w201_data *data = i2c_get_clientdata(client); | ||
110 | int nr; | ||
111 | |||
112 | mutex_lock(&data->update_lock); | ||
113 | |||
114 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | ||
115 | for (nr = 0; nr < 6; nr++) { | ||
116 | data->in[input][nr] = | ||
117 | i2c_smbus_read_byte_data(client, | ||
118 | EMC6W201_REG_IN(nr)); | ||
119 | data->in[min][nr] = | ||
120 | i2c_smbus_read_byte_data(client, | ||
121 | EMC6W201_REG_IN_LOW(nr)); | ||
122 | data->in[max][nr] = | ||
123 | i2c_smbus_read_byte_data(client, | ||
124 | EMC6W201_REG_IN_HIGH(nr)); | ||
125 | } | ||
126 | |||
127 | for (nr = 0; nr < 6; nr++) { | ||
128 | data->temp[input][nr] = | ||
129 | i2c_smbus_read_byte_data(client, | ||
130 | EMC6W201_REG_TEMP(nr)); | ||
131 | data->temp[min][nr] = | ||
132 | i2c_smbus_read_byte_data(client, | ||
133 | EMC6W201_REG_TEMP_LOW(nr)); | ||
134 | data->temp[max][nr] = | ||
135 | i2c_smbus_read_byte_data(client, | ||
136 | EMC6W201_REG_TEMP_HIGH(nr)); | ||
137 | } | ||
138 | |||
139 | for (nr = 0; nr < 5; nr++) { | ||
140 | data->fan[input][nr] = | ||
141 | emc6w201_read16(client, | ||
142 | EMC6W201_REG_FAN(nr)); | ||
143 | data->fan[min][nr] = | ||
144 | emc6w201_read16(client, | ||
145 | EMC6W201_REG_FAN_MIN(nr)); | ||
146 | } | ||
147 | |||
148 | data->last_updated = jiffies; | ||
149 | data->valid = 1; | ||
150 | } | ||
151 | |||
152 | mutex_unlock(&data->update_lock); | ||
153 | |||
154 | return data; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Sysfs callback functions | ||
159 | */ | ||
160 | |||
161 | static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 }; | ||
162 | |||
163 | static ssize_t show_in(struct device *dev, struct device_attribute *devattr, | ||
164 | char *buf) | ||
165 | { | ||
166 | struct emc6w201_data *data = emc6w201_update_device(dev); | ||
167 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
168 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
169 | |||
170 | return sprintf(buf, "%u\n", | ||
171 | (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0); | ||
172 | } | ||
173 | |||
174 | static ssize_t set_in(struct device *dev, struct device_attribute *devattr, | ||
175 | const char *buf, size_t count) | ||
176 | { | ||
177 | struct i2c_client *client = to_i2c_client(dev); | ||
178 | struct emc6w201_data *data = i2c_get_clientdata(client); | ||
179 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
180 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
181 | int err; | ||
182 | long val; | ||
183 | u8 reg; | ||
184 | |||
185 | err = strict_strtol(buf, 10, &val); | ||
186 | if (err < 0) | ||
187 | return err; | ||
188 | |||
189 | val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]); | ||
190 | reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr) | ||
191 | : EMC6W201_REG_IN_HIGH(nr); | ||
192 | |||
193 | mutex_lock(&data->update_lock); | ||
194 | data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255); | ||
195 | err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]); | ||
196 | mutex_unlock(&data->update_lock); | ||
197 | |||
198 | return err < 0 ? err : count; | ||
199 | } | ||
200 | |||
201 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | ||
202 | char *buf) | ||
203 | { | ||
204 | struct emc6w201_data *data = emc6w201_update_device(dev); | ||
205 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
206 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
207 | |||
208 | return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000); | ||
209 | } | ||
210 | |||
211 | static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, | ||
212 | const char *buf, size_t count) | ||
213 | { | ||
214 | struct i2c_client *client = to_i2c_client(dev); | ||
215 | struct emc6w201_data *data = i2c_get_clientdata(client); | ||
216 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
217 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
218 | int err; | ||
219 | long val; | ||
220 | u8 reg; | ||
221 | |||
222 | err = strict_strtol(buf, 10, &val); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | |||
226 | val /= 1000; | ||
227 | reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr) | ||
228 | : EMC6W201_REG_TEMP_HIGH(nr); | ||
229 | |||
230 | mutex_lock(&data->update_lock); | ||
231 | data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128); | ||
232 | err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]); | ||
233 | mutex_unlock(&data->update_lock); | ||
234 | |||
235 | return err < 0 ? err : count; | ||
236 | } | ||
237 | |||
238 | static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, | ||
239 | char *buf) | ||
240 | { | ||
241 | struct emc6w201_data *data = emc6w201_update_device(dev); | ||
242 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
243 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
244 | unsigned rpm; | ||
245 | |||
246 | if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF) | ||
247 | rpm = 0; | ||
248 | else | ||
249 | rpm = 5400000U / data->fan[sf][nr]; | ||
250 | |||
251 | return sprintf(buf, "%u\n", rpm); | ||
252 | } | ||
253 | |||
254 | static ssize_t set_fan(struct device *dev, struct device_attribute *devattr, | ||
255 | const char *buf, size_t count) | ||
256 | { | ||
257 | struct i2c_client *client = to_i2c_client(dev); | ||
258 | struct emc6w201_data *data = i2c_get_clientdata(client); | ||
259 | int sf = to_sensor_dev_attr_2(devattr)->index; | ||
260 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
261 | int err; | ||
262 | unsigned long val; | ||
263 | |||
264 | err = strict_strtoul(buf, 10, &val); | ||
265 | if (err < 0) | ||
266 | return err; | ||
267 | |||
268 | if (val == 0) { | ||
269 | val = 0xFFFF; | ||
270 | } else { | ||
271 | val = DIV_ROUND_CLOSEST(5400000U, val); | ||
272 | val = SENSORS_LIMIT(val, 0, 0xFFFE); | ||
273 | } | ||
274 | |||
275 | mutex_lock(&data->update_lock); | ||
276 | data->fan[sf][nr] = val; | ||
277 | err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr), | ||
278 | data->fan[sf][nr]); | ||
279 | mutex_unlock(&data->update_lock); | ||
280 | |||
281 | return err < 0 ? err : count; | ||
282 | } | ||
283 | |||
284 | static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, input); | ||
285 | static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
286 | 0, min); | ||
287 | static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
288 | 0, max); | ||
289 | static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, input); | ||
290 | static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
291 | 1, min); | ||
292 | static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
293 | 1, max); | ||
294 | static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, input); | ||
295 | static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
296 | 2, min); | ||
297 | static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
298 | 2, max); | ||
299 | static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, input); | ||
300 | static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
301 | 3, min); | ||
302 | static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
303 | 3, max); | ||
304 | static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, input); | ||
305 | static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
306 | 4, min); | ||
307 | static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
308 | 4, max); | ||
309 | static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, input); | ||
310 | static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in, | ||
311 | 5, min); | ||
312 | static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in, | ||
313 | 5, max); | ||
314 | |||
315 | static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, input); | ||
316 | static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
317 | 0, min); | ||
318 | static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
319 | 0, max); | ||
320 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, input); | ||
321 | static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
322 | 1, min); | ||
323 | static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
324 | 1, max); | ||
325 | static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, input); | ||
326 | static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
327 | 2, min); | ||
328 | static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
329 | 2, max); | ||
330 | static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, input); | ||
331 | static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
332 | 3, min); | ||
333 | static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
334 | 3, max); | ||
335 | static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, input); | ||
336 | static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
337 | 4, min); | ||
338 | static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
339 | 4, max); | ||
340 | static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, input); | ||
341 | static SENSOR_DEVICE_ATTR_2(temp6_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
342 | 5, min); | ||
343 | static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
344 | 5, max); | ||
345 | |||
346 | static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, input); | ||
347 | static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan, | ||
348 | 0, min); | ||
349 | static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, input); | ||
350 | static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan, | ||
351 | 1, min); | ||
352 | static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, input); | ||
353 | static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan, | ||
354 | 2, min); | ||
355 | static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, input); | ||
356 | static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan, | ||
357 | 3, min); | ||
358 | static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input); | ||
359 | static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan, | ||
360 | 4, min); | ||
361 | |||
362 | static struct attribute *emc6w201_attributes[] = { | ||
363 | &sensor_dev_attr_in0_input.dev_attr.attr, | ||
364 | &sensor_dev_attr_in0_min.dev_attr.attr, | ||
365 | &sensor_dev_attr_in0_max.dev_attr.attr, | ||
366 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
367 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
368 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
369 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
370 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
371 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
372 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
373 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
374 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
375 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
376 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
377 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
378 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
379 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
380 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
381 | |||
382 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
383 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
384 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
385 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
386 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
387 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
388 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
389 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
390 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
391 | &sensor_dev_attr_temp4_input.dev_attr.attr, | ||
392 | &sensor_dev_attr_temp4_min.dev_attr.attr, | ||
393 | &sensor_dev_attr_temp4_max.dev_attr.attr, | ||
394 | &sensor_dev_attr_temp5_input.dev_attr.attr, | ||
395 | &sensor_dev_attr_temp5_min.dev_attr.attr, | ||
396 | &sensor_dev_attr_temp5_max.dev_attr.attr, | ||
397 | &sensor_dev_attr_temp6_input.dev_attr.attr, | ||
398 | &sensor_dev_attr_temp6_min.dev_attr.attr, | ||
399 | &sensor_dev_attr_temp6_max.dev_attr.attr, | ||
400 | |||
401 | &sensor_dev_attr_fan1_input.dev_attr.attr, | ||
402 | &sensor_dev_attr_fan1_min.dev_attr.attr, | ||
403 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
404 | &sensor_dev_attr_fan2_min.dev_attr.attr, | ||
405 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
406 | &sensor_dev_attr_fan3_min.dev_attr.attr, | ||
407 | &sensor_dev_attr_fan4_input.dev_attr.attr, | ||
408 | &sensor_dev_attr_fan4_min.dev_attr.attr, | ||
409 | &sensor_dev_attr_fan5_input.dev_attr.attr, | ||
410 | &sensor_dev_attr_fan5_min.dev_attr.attr, | ||
411 | NULL | ||
412 | }; | ||
413 | |||
414 | static const struct attribute_group emc6w201_group = { | ||
415 | .attrs = emc6w201_attributes, | ||
416 | }; | ||
417 | |||
418 | /* | ||
419 | * Driver interface | ||
420 | */ | ||
421 | |||
422 | /* Return 0 if detection is successful, -ENODEV otherwise */ | ||
423 | static int emc6w201_detect(struct i2c_client *client, | ||
424 | struct i2c_board_info *info) | ||
425 | { | ||
426 | struct i2c_adapter *adapter = client->adapter; | ||
427 | int company, verstep, config; | ||
428 | |||
429 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
430 | return -ENODEV; | ||
431 | |||
432 | /* Identification */ | ||
433 | company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY); | ||
434 | if (company != 0x5C) | ||
435 | return -ENODEV; | ||
436 | verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP); | ||
437 | if (verstep < 0 || (verstep & 0xF0) != 0xB0) | ||
438 | return -ENODEV; | ||
439 | if ((verstep & 0x0F) > 2) { | ||
440 | dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n", | ||
441 | verstep & 0x0F); | ||
442 | return -ENODEV; | ||
443 | } | ||
444 | |||
445 | /* Check configuration */ | ||
446 | config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG); | ||
447 | if ((config & 0xF4) != 0x04) | ||
448 | return -ENODEV; | ||
449 | if (!(config & 0x01)) { | ||
450 | dev_err(&client->dev, "Monitoring not enabled\n"); | ||
451 | return -ENODEV; | ||
452 | } | ||
453 | |||
454 | strlcpy(info->type, "emc6w201", I2C_NAME_SIZE); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int emc6w201_probe(struct i2c_client *client, | ||
460 | const struct i2c_device_id *id) | ||
461 | { | ||
462 | struct emc6w201_data *data; | ||
463 | int err; | ||
464 | |||
465 | data = kzalloc(sizeof(struct emc6w201_data), GFP_KERNEL); | ||
466 | if (!data) { | ||
467 | err = -ENOMEM; | ||
468 | goto exit; | ||
469 | } | ||
470 | |||
471 | i2c_set_clientdata(client, data); | ||
472 | mutex_init(&data->update_lock); | ||
473 | |||
474 | /* Create sysfs attribute */ | ||
475 | err = sysfs_create_group(&client->dev.kobj, &emc6w201_group); | ||
476 | if (err) | ||
477 | goto exit_free; | ||
478 | |||
479 | /* Expose as a hwmon device */ | ||
480 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
481 | if (IS_ERR(data->hwmon_dev)) { | ||
482 | err = PTR_ERR(data->hwmon_dev); | ||
483 | goto exit_remove; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | |||
488 | exit_remove: | ||
489 | sysfs_remove_group(&client->dev.kobj, &emc6w201_group); | ||
490 | exit_free: | ||
491 | kfree(data); | ||
492 | exit: | ||
493 | return err; | ||
494 | } | ||
495 | |||
496 | static int emc6w201_remove(struct i2c_client *client) | ||
497 | { | ||
498 | struct emc6w201_data *data = i2c_get_clientdata(client); | ||
499 | |||
500 | hwmon_device_unregister(data->hwmon_dev); | ||
501 | sysfs_remove_group(&client->dev.kobj, &emc6w201_group); | ||
502 | kfree(data); | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static const struct i2c_device_id emc6w201_id[] = { | ||
508 | { "emc6w201", 0 }, | ||
509 | { } | ||
510 | }; | ||
511 | MODULE_DEVICE_TABLE(i2c, emc6w201_id); | ||
512 | |||
513 | static struct i2c_driver emc6w201_driver = { | ||
514 | .class = I2C_CLASS_HWMON, | ||
515 | .driver = { | ||
516 | .name = "emc6w201", | ||
517 | }, | ||
518 | .probe = emc6w201_probe, | ||
519 | .remove = emc6w201_remove, | ||
520 | .id_table = emc6w201_id, | ||
521 | .detect = emc6w201_detect, | ||
522 | .address_list = normal_i2c, | ||
523 | }; | ||
524 | |||
525 | static int __init sensors_emc6w201_init(void) | ||
526 | { | ||
527 | return i2c_add_driver(&emc6w201_driver); | ||
528 | } | ||
529 | module_init(sensors_emc6w201_init); | ||
530 | |||
531 | static void __exit sensors_emc6w201_exit(void) | ||
532 | { | ||
533 | i2c_del_driver(&emc6w201_driver); | ||
534 | } | ||
535 | module_exit(sensors_emc6w201_exit); | ||
536 | |||
537 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); | ||
538 | MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver"); | ||
539 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index ca07a32447c2..a4a94a096c90 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c | |||
@@ -48,6 +48,7 @@ | |||
48 | 48 | ||
49 | #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ | 49 | #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ |
50 | #define SIO_F71808E_ID 0x0901 /* Chipset ID */ | 50 | #define SIO_F71808E_ID 0x0901 /* Chipset ID */ |
51 | #define SIO_F71808A_ID 0x1001 /* Chipset ID */ | ||
51 | #define SIO_F71858_ID 0x0507 /* Chipset ID */ | 52 | #define SIO_F71858_ID 0x0507 /* Chipset ID */ |
52 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ | 53 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ |
53 | #define SIO_F71869_ID 0x0814 /* Chipset ID */ | 54 | #define SIO_F71869_ID 0x0814 /* Chipset ID */ |
@@ -107,11 +108,12 @@ static unsigned short force_id; | |||
107 | module_param(force_id, ushort, 0); | 108 | module_param(force_id, ushort, 0); |
108 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); | 109 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); |
109 | 110 | ||
110 | enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg, | 111 | enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg, |
111 | f71889ed, f71889a, f8000, f81865f }; | 112 | f71889ed, f71889a, f8000, f81865f }; |
112 | 113 | ||
113 | static const char *f71882fg_names[] = { | 114 | static const char *f71882fg_names[] = { |
114 | "f71808e", | 115 | "f71808e", |
116 | "f71808a", | ||
115 | "f71858fg", | 117 | "f71858fg", |
116 | "f71862fg", | 118 | "f71862fg", |
117 | "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ | 119 | "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ |
@@ -125,6 +127,7 @@ static const char *f71882fg_names[] = { | |||
125 | 127 | ||
126 | static const char f71882fg_has_in[][F71882FG_MAX_INS] = { | 128 | static const char f71882fg_has_in[][F71882FG_MAX_INS] = { |
127 | [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, | 129 | [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, |
130 | [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 }, | ||
128 | [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, | 131 | [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, |
129 | [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, | 132 | [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
130 | [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, | 133 | [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
@@ -138,6 +141,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = { | |||
138 | 141 | ||
139 | static const char f71882fg_has_in1_alarm[] = { | 142 | static const char f71882fg_has_in1_alarm[] = { |
140 | [f71808e] = 0, | 143 | [f71808e] = 0, |
144 | [f71808a] = 0, | ||
141 | [f71858fg] = 0, | 145 | [f71858fg] = 0, |
142 | [f71862fg] = 0, | 146 | [f71862fg] = 0, |
143 | [f71869] = 0, | 147 | [f71869] = 0, |
@@ -149,8 +153,9 @@ static const char f71882fg_has_in1_alarm[] = { | |||
149 | [f81865f] = 1, | 153 | [f81865f] = 1, |
150 | }; | 154 | }; |
151 | 155 | ||
152 | static const char f71882fg_has_beep[] = { | 156 | static const char f71882fg_fan_has_beep[] = { |
153 | [f71808e] = 0, | 157 | [f71808e] = 0, |
158 | [f71808a] = 0, | ||
154 | [f71858fg] = 0, | 159 | [f71858fg] = 0, |
155 | [f71862fg] = 1, | 160 | [f71862fg] = 1, |
156 | [f71869] = 1, | 161 | [f71869] = 1, |
@@ -164,6 +169,7 @@ static const char f71882fg_has_beep[] = { | |||
164 | 169 | ||
165 | static const char f71882fg_nr_fans[] = { | 170 | static const char f71882fg_nr_fans[] = { |
166 | [f71808e] = 3, | 171 | [f71808e] = 3, |
172 | [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */ | ||
167 | [f71858fg] = 3, | 173 | [f71858fg] = 3, |
168 | [f71862fg] = 3, | 174 | [f71862fg] = 3, |
169 | [f71869] = 3, | 175 | [f71869] = 3, |
@@ -171,12 +177,27 @@ static const char f71882fg_nr_fans[] = { | |||
171 | [f71889fg] = 3, | 177 | [f71889fg] = 3, |
172 | [f71889ed] = 3, | 178 | [f71889ed] = 3, |
173 | [f71889a] = 3, | 179 | [f71889a] = 3, |
174 | [f8000] = 3, | 180 | [f8000] = 3, /* +1 fan which is monitor only */ |
175 | [f81865f] = 2, | 181 | [f81865f] = 2, |
176 | }; | 182 | }; |
177 | 183 | ||
184 | static const char f71882fg_temp_has_beep[] = { | ||
185 | [f71808e] = 0, | ||
186 | [f71808a] = 1, | ||
187 | [f71858fg] = 0, | ||
188 | [f71862fg] = 1, | ||
189 | [f71869] = 1, | ||
190 | [f71882fg] = 1, | ||
191 | [f71889fg] = 1, | ||
192 | [f71889ed] = 1, | ||
193 | [f71889a] = 1, | ||
194 | [f8000] = 0, | ||
195 | [f81865f] = 1, | ||
196 | }; | ||
197 | |||
178 | static const char f71882fg_nr_temps[] = { | 198 | static const char f71882fg_nr_temps[] = { |
179 | [f71808e] = 2, | 199 | [f71808e] = 2, |
200 | [f71808a] = 2, | ||
180 | [f71858fg] = 3, | 201 | [f71858fg] = 3, |
181 | [f71862fg] = 3, | 202 | [f71862fg] = 3, |
182 | [f71869] = 3, | 203 | [f71869] = 3, |
@@ -301,6 +322,10 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, | |||
301 | char *buf); | 322 | char *buf); |
302 | static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, | 323 | static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, |
303 | const char *buf, size_t count); | 324 | const char *buf, size_t count); |
325 | static ssize_t show_simple_pwm(struct device *dev, | ||
326 | struct device_attribute *devattr, char *buf); | ||
327 | static ssize_t store_simple_pwm(struct device *dev, | ||
328 | struct device_attribute *devattr, const char *buf, size_t count); | ||
304 | static ssize_t show_pwm_enable(struct device *dev, | 329 | static ssize_t show_pwm_enable(struct device *dev, |
305 | struct device_attribute *devattr, char *buf); | 330 | struct device_attribute *devattr, char *buf); |
306 | static ssize_t store_pwm_enable(struct device *dev, | 331 | static ssize_t store_pwm_enable(struct device *dev, |
@@ -550,6 +575,14 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { { | |||
550 | show_pwm_interpolate, store_pwm_interpolate, 0, 3), | 575 | show_pwm_interpolate, store_pwm_interpolate, 0, 3), |
551 | } }; | 576 | } }; |
552 | 577 | ||
578 | /* Attr for the third fan of the f71808a, which only has manual pwm */ | ||
579 | static struct sensor_device_attribute_2 f71808a_fan3_attr[] = { | ||
580 | SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2), | ||
581 | SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2), | ||
582 | SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, | ||
583 | show_simple_pwm, store_simple_pwm, 0, 2), | ||
584 | }; | ||
585 | |||
553 | /* Attr for models which can beep on Fan alarm */ | 586 | /* Attr for models which can beep on Fan alarm */ |
554 | static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { | 587 | static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { |
555 | SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, | 588 | SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, |
@@ -1146,12 +1179,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
1146 | data->temp_type[3] = (reg & 0x08) ? 2 : 4; | 1179 | data->temp_type[3] = (reg & 0x08) ? 2 : 4; |
1147 | } | 1180 | } |
1148 | 1181 | ||
1149 | if (f71882fg_has_beep[data->type]) { | 1182 | if (f71882fg_fan_has_beep[data->type]) |
1150 | data->fan_beep = f71882fg_read8(data, | 1183 | data->fan_beep = f71882fg_read8(data, |
1151 | F71882FG_REG_FAN_BEEP); | 1184 | F71882FG_REG_FAN_BEEP); |
1185 | |||
1186 | if (f71882fg_temp_has_beep[data->type]) | ||
1152 | data->temp_beep = f71882fg_read8(data, | 1187 | data->temp_beep = f71882fg_read8(data, |
1153 | F71882FG_REG_TEMP_BEEP); | 1188 | F71882FG_REG_TEMP_BEEP); |
1154 | } | ||
1155 | 1189 | ||
1156 | data->pwm_enable = f71882fg_read8(data, | 1190 | data->pwm_enable = f71882fg_read8(data, |
1157 | F71882FG_REG_PWM_ENABLE); | 1191 | F71882FG_REG_PWM_ENABLE); |
@@ -1232,7 +1266,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
1232 | data->pwm[nr] = | 1266 | data->pwm[nr] = |
1233 | f71882fg_read8(data, F71882FG_REG_PWM(nr)); | 1267 | f71882fg_read8(data, F71882FG_REG_PWM(nr)); |
1234 | } | 1268 | } |
1235 | /* The f8000 can monitor 1 more fan, but has no pwm for it */ | 1269 | /* Some models have 1 more fan with limited capabilities */ |
1270 | if (data->type == f71808a) { | ||
1271 | data->fan[2] = f71882fg_read16(data, | ||
1272 | F71882FG_REG_FAN(2)); | ||
1273 | data->pwm[2] = f71882fg_read8(data, | ||
1274 | F71882FG_REG_PWM(2)); | ||
1275 | } | ||
1236 | if (data->type == f8000) | 1276 | if (data->type == f8000) |
1237 | data->fan[3] = f71882fg_read16(data, | 1277 | data->fan[3] = f71882fg_read16(data, |
1238 | F71882FG_REG_FAN(3)); | 1278 | F71882FG_REG_FAN(3)); |
@@ -1722,6 +1762,38 @@ leave: | |||
1722 | return count; | 1762 | return count; |
1723 | } | 1763 | } |
1724 | 1764 | ||
1765 | static ssize_t show_simple_pwm(struct device *dev, | ||
1766 | struct device_attribute *devattr, char *buf) | ||
1767 | { | ||
1768 | struct f71882fg_data *data = f71882fg_update_device(dev); | ||
1769 | int val, nr = to_sensor_dev_attr_2(devattr)->index; | ||
1770 | |||
1771 | val = data->pwm[nr]; | ||
1772 | return sprintf(buf, "%d\n", val); | ||
1773 | } | ||
1774 | |||
1775 | static ssize_t store_simple_pwm(struct device *dev, | ||
1776 | struct device_attribute *devattr, | ||
1777 | const char *buf, size_t count) | ||
1778 | { | ||
1779 | struct f71882fg_data *data = dev_get_drvdata(dev); | ||
1780 | int err, nr = to_sensor_dev_attr_2(devattr)->index; | ||
1781 | long val; | ||
1782 | |||
1783 | err = strict_strtol(buf, 10, &val); | ||
1784 | if (err) | ||
1785 | return err; | ||
1786 | |||
1787 | val = SENSORS_LIMIT(val, 0, 255); | ||
1788 | |||
1789 | mutex_lock(&data->update_lock); | ||
1790 | f71882fg_write8(data, F71882FG_REG_PWM(nr), val); | ||
1791 | data->pwm[nr] = val; | ||
1792 | mutex_unlock(&data->update_lock); | ||
1793 | |||
1794 | return count; | ||
1795 | } | ||
1796 | |||
1725 | static ssize_t show_pwm_enable(struct device *dev, | 1797 | static ssize_t show_pwm_enable(struct device *dev, |
1726 | struct device_attribute *devattr, char *buf) | 1798 | struct device_attribute *devattr, char *buf) |
1727 | { | 1799 | { |
@@ -2140,7 +2212,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2140 | if (err) | 2212 | if (err) |
2141 | goto exit_unregister_sysfs; | 2213 | goto exit_unregister_sysfs; |
2142 | 2214 | ||
2143 | if (f71882fg_has_beep[data->type]) { | 2215 | if (f71882fg_temp_has_beep[data->type]) { |
2144 | err = f71882fg_create_sysfs_files(pdev, | 2216 | err = f71882fg_create_sysfs_files(pdev, |
2145 | &fxxxx_temp_beep_attr[0][0], | 2217 | &fxxxx_temp_beep_attr[0][0], |
2146 | ARRAY_SIZE(fxxxx_temp_beep_attr[0]) | 2218 | ARRAY_SIZE(fxxxx_temp_beep_attr[0]) |
@@ -2169,6 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2169 | if (start_reg & 0x02) { | 2241 | if (start_reg & 0x02) { |
2170 | switch (data->type) { | 2242 | switch (data->type) { |
2171 | case f71808e: | 2243 | case f71808e: |
2244 | case f71808a: | ||
2172 | case f71869: | 2245 | case f71869: |
2173 | /* These always have signed auto point temps */ | 2246 | /* These always have signed auto point temps */ |
2174 | data->auto_point_temp_signed = 1; | 2247 | data->auto_point_temp_signed = 1; |
@@ -2221,7 +2294,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2221 | if (err) | 2294 | if (err) |
2222 | goto exit_unregister_sysfs; | 2295 | goto exit_unregister_sysfs; |
2223 | 2296 | ||
2224 | if (f71882fg_has_beep[data->type]) { | 2297 | if (f71882fg_fan_has_beep[data->type]) { |
2225 | err = f71882fg_create_sysfs_files(pdev, | 2298 | err = f71882fg_create_sysfs_files(pdev, |
2226 | fxxxx_fan_beep_attr, nr_fans); | 2299 | fxxxx_fan_beep_attr, nr_fans); |
2227 | if (err) | 2300 | if (err) |
@@ -2230,6 +2303,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2230 | 2303 | ||
2231 | switch (data->type) { | 2304 | switch (data->type) { |
2232 | case f71808e: | 2305 | case f71808e: |
2306 | case f71808a: | ||
2233 | case f71869: | 2307 | case f71869: |
2234 | case f71889fg: | 2308 | case f71889fg: |
2235 | case f71889ed: | 2309 | case f71889ed: |
@@ -2255,6 +2329,16 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2255 | } | 2329 | } |
2256 | 2330 | ||
2257 | switch (data->type) { | 2331 | switch (data->type) { |
2332 | case f71808a: | ||
2333 | err = f71882fg_create_sysfs_files(pdev, | ||
2334 | &fxxxx_auto_pwm_attr[0][0], | ||
2335 | ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); | ||
2336 | if (err) | ||
2337 | goto exit_unregister_sysfs; | ||
2338 | err = f71882fg_create_sysfs_files(pdev, | ||
2339 | f71808a_fan3_attr, | ||
2340 | ARRAY_SIZE(f71808a_fan3_attr)); | ||
2341 | break; | ||
2258 | case f71862fg: | 2342 | case f71862fg: |
2259 | err = f71882fg_create_sysfs_files(pdev, | 2343 | err = f71882fg_create_sysfs_files(pdev, |
2260 | f71862fg_auto_pwm_attr, | 2344 | f71862fg_auto_pwm_attr, |
@@ -2343,7 +2427,7 @@ static int f71882fg_remove(struct platform_device *pdev) | |||
2343 | &fxxxx_temp_attr[0][0], | 2427 | &fxxxx_temp_attr[0][0], |
2344 | ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); | 2428 | ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); |
2345 | } | 2429 | } |
2346 | if (f71882fg_has_beep[data->type]) { | 2430 | if (f71882fg_temp_has_beep[data->type]) { |
2347 | f71882fg_remove_sysfs_files(pdev, | 2431 | f71882fg_remove_sysfs_files(pdev, |
2348 | &fxxxx_temp_beep_attr[0][0], | 2432 | &fxxxx_temp_beep_attr[0][0], |
2349 | ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps); | 2433 | ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps); |
@@ -2366,12 +2450,20 @@ static int f71882fg_remove(struct platform_device *pdev) | |||
2366 | f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0], | 2450 | f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0], |
2367 | ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans); | 2451 | ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans); |
2368 | 2452 | ||
2369 | if (f71882fg_has_beep[data->type]) { | 2453 | if (f71882fg_fan_has_beep[data->type]) { |
2370 | f71882fg_remove_sysfs_files(pdev, | 2454 | f71882fg_remove_sysfs_files(pdev, |
2371 | fxxxx_fan_beep_attr, nr_fans); | 2455 | fxxxx_fan_beep_attr, nr_fans); |
2372 | } | 2456 | } |
2373 | 2457 | ||
2374 | switch (data->type) { | 2458 | switch (data->type) { |
2459 | case f71808a: | ||
2460 | f71882fg_remove_sysfs_files(pdev, | ||
2461 | &fxxxx_auto_pwm_attr[0][0], | ||
2462 | ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); | ||
2463 | f71882fg_remove_sysfs_files(pdev, | ||
2464 | f71808a_fan3_attr, | ||
2465 | ARRAY_SIZE(f71808a_fan3_attr)); | ||
2466 | break; | ||
2375 | case f71862fg: | 2467 | case f71862fg: |
2376 | f71882fg_remove_sysfs_files(pdev, | 2468 | f71882fg_remove_sysfs_files(pdev, |
2377 | f71862fg_auto_pwm_attr, | 2469 | f71862fg_auto_pwm_attr, |
@@ -2424,6 +2516,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, | |||
2424 | case SIO_F71808E_ID: | 2516 | case SIO_F71808E_ID: |
2425 | sio_data->type = f71808e; | 2517 | sio_data->type = f71808e; |
2426 | break; | 2518 | break; |
2519 | case SIO_F71808A_ID: | ||
2520 | sio_data->type = f71808a; | ||
2521 | break; | ||
2427 | case SIO_F71858_ID: | 2522 | case SIO_F71858_ID: |
2428 | sio_data->type = f71858fg; | 2523 | sio_data->type = f71858fg; |
2429 | break; | 2524 | break; |
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c new file mode 100644 index 000000000000..523f8fb9e7d9 --- /dev/null +++ b/drivers/hwmon/fam15h_power.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * fam15h_power.c - AMD Family 15h processor power monitoring | ||
3 | * | ||
4 | * Copyright (c) 2011 Advanced Micro Devices, Inc. | ||
5 | * Author: Andreas Herrmann <andreas.herrmann3@amd.com> | ||
6 | * | ||
7 | * | ||
8 | * This driver is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This driver is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | * See the GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this driver; if not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/err.h> | ||
22 | #include <linux/hwmon.h> | ||
23 | #include <linux/hwmon-sysfs.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/bitops.h> | ||
28 | #include <asm/processor.h> | ||
29 | |||
30 | MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); | ||
31 | MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | /* D18F3 */ | ||
35 | #define REG_NORTHBRIDGE_CAP 0xe8 | ||
36 | |||
37 | /* D18F4 */ | ||
38 | #define REG_PROCESSOR_TDP 0x1b8 | ||
39 | |||
40 | /* D18F5 */ | ||
41 | #define REG_TDP_RUNNING_AVERAGE 0xe0 | ||
42 | #define REG_TDP_LIMIT3 0xe8 | ||
43 | |||
44 | struct fam15h_power_data { | ||
45 | struct device *hwmon_dev; | ||
46 | unsigned int tdp_to_watts; | ||
47 | unsigned int base_tdp; | ||
48 | unsigned int processor_pwr_watts; | ||
49 | }; | ||
50 | |||
51 | static ssize_t show_power(struct device *dev, | ||
52 | struct device_attribute *attr, char *buf) | ||
53 | { | ||
54 | u32 val, tdp_limit, running_avg_range; | ||
55 | s32 running_avg_capture; | ||
56 | u64 curr_pwr_watts; | ||
57 | struct pci_dev *f4 = to_pci_dev(dev); | ||
58 | struct fam15h_power_data *data = dev_get_drvdata(dev); | ||
59 | |||
60 | pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), | ||
61 | REG_TDP_RUNNING_AVERAGE, &val); | ||
62 | running_avg_capture = (val >> 4) & 0x3fffff; | ||
63 | running_avg_capture = sign_extend32(running_avg_capture, 22); | ||
64 | running_avg_range = val & 0xf; | ||
65 | |||
66 | pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), | ||
67 | REG_TDP_LIMIT3, &val); | ||
68 | |||
69 | tdp_limit = val >> 16; | ||
70 | curr_pwr_watts = tdp_limit + data->base_tdp - | ||
71 | (s32)(running_avg_capture >> (running_avg_range + 1)); | ||
72 | curr_pwr_watts *= data->tdp_to_watts; | ||
73 | |||
74 | /* | ||
75 | * Convert to microWatt | ||
76 | * | ||
77 | * power is in Watt provided as fixed point integer with | ||
78 | * scaling factor 1/(2^16). For conversion we use | ||
79 | * (10^6)/(2^16) = 15625/(2^10) | ||
80 | */ | ||
81 | curr_pwr_watts = (curr_pwr_watts * 15625) >> 10; | ||
82 | return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts); | ||
83 | } | ||
84 | static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL); | ||
85 | |||
86 | static ssize_t show_power_crit(struct device *dev, | ||
87 | struct device_attribute *attr, char *buf) | ||
88 | { | ||
89 | struct fam15h_power_data *data = dev_get_drvdata(dev); | ||
90 | |||
91 | return sprintf(buf, "%u\n", data->processor_pwr_watts); | ||
92 | } | ||
93 | static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL); | ||
94 | |||
95 | static ssize_t show_name(struct device *dev, | ||
96 | struct device_attribute *attr, char *buf) | ||
97 | { | ||
98 | return sprintf(buf, "fam15h_power\n"); | ||
99 | } | ||
100 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
101 | |||
102 | static struct attribute *fam15h_power_attrs[] = { | ||
103 | &dev_attr_power1_input.attr, | ||
104 | &dev_attr_power1_crit.attr, | ||
105 | &dev_attr_name.attr, | ||
106 | NULL | ||
107 | }; | ||
108 | |||
109 | static const struct attribute_group fam15h_power_attr_group = { | ||
110 | .attrs = fam15h_power_attrs, | ||
111 | }; | ||
112 | |||
113 | static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) | ||
114 | { | ||
115 | u32 val; | ||
116 | |||
117 | pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3), | ||
118 | REG_NORTHBRIDGE_CAP, &val); | ||
119 | if ((val & BIT(29)) && ((val >> 30) & 3)) | ||
120 | return false; | ||
121 | |||
122 | return true; | ||
123 | } | ||
124 | |||
125 | static void __devinit fam15h_power_init_data(struct pci_dev *f4, | ||
126 | struct fam15h_power_data *data) | ||
127 | { | ||
128 | u32 val; | ||
129 | u64 tmp; | ||
130 | |||
131 | pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val); | ||
132 | data->base_tdp = val >> 16; | ||
133 | tmp = val & 0xffff; | ||
134 | |||
135 | pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), | ||
136 | REG_TDP_LIMIT3, &val); | ||
137 | |||
138 | data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f); | ||
139 | tmp *= data->tdp_to_watts; | ||
140 | |||
141 | /* result not allowed to be >= 256W */ | ||
142 | if ((tmp >> 16) >= 256) | ||
143 | dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts " | ||
144 | "(processor_pwr_watts>=%u)\n", | ||
145 | (unsigned int) (tmp >> 16)); | ||
146 | |||
147 | /* convert to microWatt */ | ||
148 | data->processor_pwr_watts = (tmp * 15625) >> 10; | ||
149 | } | ||
150 | |||
151 | static int __devinit fam15h_power_probe(struct pci_dev *pdev, | ||
152 | const struct pci_device_id *id) | ||
153 | { | ||
154 | struct fam15h_power_data *data; | ||
155 | struct device *dev; | ||
156 | int err; | ||
157 | |||
158 | if (!fam15h_power_is_internal_node0(pdev)) { | ||
159 | err = -ENODEV; | ||
160 | goto exit; | ||
161 | } | ||
162 | |||
163 | data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL); | ||
164 | if (!data) { | ||
165 | err = -ENOMEM; | ||
166 | goto exit; | ||
167 | } | ||
168 | fam15h_power_init_data(pdev, data); | ||
169 | dev = &pdev->dev; | ||
170 | |||
171 | dev_set_drvdata(dev, data); | ||
172 | err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group); | ||
173 | if (err) | ||
174 | goto exit_free_data; | ||
175 | |||
176 | data->hwmon_dev = hwmon_device_register(dev); | ||
177 | if (IS_ERR(data->hwmon_dev)) { | ||
178 | err = PTR_ERR(data->hwmon_dev); | ||
179 | goto exit_remove_group; | ||
180 | } | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | exit_remove_group: | ||
185 | sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group); | ||
186 | exit_free_data: | ||
187 | kfree(data); | ||
188 | exit: | ||
189 | return err; | ||
190 | } | ||
191 | |||
192 | static void __devexit fam15h_power_remove(struct pci_dev *pdev) | ||
193 | { | ||
194 | struct device *dev; | ||
195 | struct fam15h_power_data *data; | ||
196 | |||
197 | dev = &pdev->dev; | ||
198 | data = dev_get_drvdata(dev); | ||
199 | hwmon_device_unregister(data->hwmon_dev); | ||
200 | sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group); | ||
201 | dev_set_drvdata(dev, NULL); | ||
202 | kfree(data); | ||
203 | } | ||
204 | |||
205 | static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = { | ||
206 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, | ||
207 | {} | ||
208 | }; | ||
209 | MODULE_DEVICE_TABLE(pci, fam15h_power_id_table); | ||
210 | |||
211 | static struct pci_driver fam15h_power_driver = { | ||
212 | .name = "fam15h_power", | ||
213 | .id_table = fam15h_power_id_table, | ||
214 | .probe = fam15h_power_probe, | ||
215 | .remove = __devexit_p(fam15h_power_remove), | ||
216 | }; | ||
217 | |||
218 | static int __init fam15h_power_init(void) | ||
219 | { | ||
220 | return pci_register_driver(&fam15h_power_driver); | ||
221 | } | ||
222 | |||
223 | static void __exit fam15h_power_exit(void) | ||
224 | { | ||
225 | pci_unregister_driver(&fam15h_power_driver); | ||
226 | } | ||
227 | |||
228 | module_init(fam15h_power_init) | ||
229 | module_exit(fam15h_power_exit) | ||
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index bc6e2ab3a361..537409d07ee7 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c | |||
@@ -523,7 +523,7 @@ static void aem_delete(struct aem_data *data) | |||
523 | aem_remove_sensors(data); | 523 | aem_remove_sensors(data); |
524 | hwmon_device_unregister(data->hwmon_dev); | 524 | hwmon_device_unregister(data->hwmon_dev); |
525 | ipmi_destroy_user(data->ipmi.user); | 525 | ipmi_destroy_user(data->ipmi.user); |
526 | dev_set_drvdata(&data->pdev->dev, NULL); | 526 | platform_set_drvdata(data->pdev, NULL); |
527 | platform_device_unregister(data->pdev); | 527 | platform_device_unregister(data->pdev); |
528 | aem_idr_put(data->id); | 528 | aem_idr_put(data->id); |
529 | kfree(data); | 529 | kfree(data); |
@@ -594,7 +594,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) | |||
594 | if (res) | 594 | if (res) |
595 | goto ipmi_err; | 595 | goto ipmi_err; |
596 | 596 | ||
597 | dev_set_drvdata(&data->pdev->dev, data); | 597 | platform_set_drvdata(data->pdev, data); |
598 | 598 | ||
599 | /* Set up IPMI interface */ | 599 | /* Set up IPMI interface */ |
600 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, | 600 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, |
@@ -630,7 +630,7 @@ sensor_err: | |||
630 | hwmon_reg_err: | 630 | hwmon_reg_err: |
631 | ipmi_destroy_user(data->ipmi.user); | 631 | ipmi_destroy_user(data->ipmi.user); |
632 | ipmi_err: | 632 | ipmi_err: |
633 | dev_set_drvdata(&data->pdev->dev, NULL); | 633 | platform_set_drvdata(data->pdev, NULL); |
634 | platform_device_unregister(data->pdev); | 634 | platform_device_unregister(data->pdev); |
635 | dev_err: | 635 | dev_err: |
636 | aem_idr_put(data->id); | 636 | aem_idr_put(data->id); |
@@ -727,7 +727,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, | |||
727 | if (res) | 727 | if (res) |
728 | goto ipmi_err; | 728 | goto ipmi_err; |
729 | 729 | ||
730 | dev_set_drvdata(&data->pdev->dev, data); | 730 | platform_set_drvdata(data->pdev, data); |
731 | 731 | ||
732 | /* Set up IPMI interface */ | 732 | /* Set up IPMI interface */ |
733 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, | 733 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, |
@@ -763,7 +763,7 @@ sensor_err: | |||
763 | hwmon_reg_err: | 763 | hwmon_reg_err: |
764 | ipmi_destroy_user(data->ipmi.user); | 764 | ipmi_destroy_user(data->ipmi.user); |
765 | ipmi_err: | 765 | ipmi_err: |
766 | dev_set_drvdata(&data->pdev->dev, NULL); | 766 | platform_set_drvdata(data->pdev, NULL); |
767 | platform_device_unregister(data->pdev); | 767 | platform_device_unregister(data->pdev); |
768 | dev_err: | 768 | dev_err: |
769 | aem_idr_put(data->id); | 769 | aem_idr_put(data->id); |
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 316b64823f7b..bb6405b92007 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -77,15 +77,13 @@ static struct platform_device *pdev; | |||
77 | #define DEVID 0x20 /* Register: Device ID */ | 77 | #define DEVID 0x20 /* Register: Device ID */ |
78 | #define DEVREV 0x22 /* Register: Device Revision */ | 78 | #define DEVREV 0x22 /* Register: Device Revision */ |
79 | 79 | ||
80 | static inline int | 80 | static inline int superio_inb(int reg) |
81 | superio_inb(int reg) | ||
82 | { | 81 | { |
83 | outb(reg, REG); | 82 | outb(reg, REG); |
84 | return inb(VAL); | 83 | return inb(VAL); |
85 | } | 84 | } |
86 | 85 | ||
87 | static inline void | 86 | static inline void superio_outb(int reg, int val) |
88 | superio_outb(int reg, int val) | ||
89 | { | 87 | { |
90 | outb(reg, REG); | 88 | outb(reg, REG); |
91 | outb(val, VAL); | 89 | outb(val, VAL); |
@@ -101,27 +99,32 @@ static int superio_inw(int reg) | |||
101 | return val; | 99 | return val; |
102 | } | 100 | } |
103 | 101 | ||
104 | static inline void | 102 | static inline void superio_select(int ldn) |
105 | superio_select(int ldn) | ||
106 | { | 103 | { |
107 | outb(DEV, REG); | 104 | outb(DEV, REG); |
108 | outb(ldn, VAL); | 105 | outb(ldn, VAL); |
109 | } | 106 | } |
110 | 107 | ||
111 | static inline void | 108 | static inline int superio_enter(void) |
112 | superio_enter(void) | ||
113 | { | 109 | { |
110 | /* | ||
111 | * Try to reserve REG and REG + 1 for exclusive access. | ||
112 | */ | ||
113 | if (!request_muxed_region(REG, 2, DRVNAME)) | ||
114 | return -EBUSY; | ||
115 | |||
114 | outb(0x87, REG); | 116 | outb(0x87, REG); |
115 | outb(0x01, REG); | 117 | outb(0x01, REG); |
116 | outb(0x55, REG); | 118 | outb(0x55, REG); |
117 | outb(0x55, REG); | 119 | outb(0x55, REG); |
120 | return 0; | ||
118 | } | 121 | } |
119 | 122 | ||
120 | static inline void | 123 | static inline void superio_exit(void) |
121 | superio_exit(void) | ||
122 | { | 124 | { |
123 | outb(0x02, REG); | 125 | outb(0x02, REG); |
124 | outb(0x02, VAL); | 126 | outb(0x02, VAL); |
127 | release_region(REG, 2); | ||
125 | } | 128 | } |
126 | 129 | ||
127 | /* Logical device 4 registers */ | 130 | /* Logical device 4 registers */ |
@@ -1542,11 +1545,15 @@ static const struct attribute_group it87_group_label = { | |||
1542 | static int __init it87_find(unsigned short *address, | 1545 | static int __init it87_find(unsigned short *address, |
1543 | struct it87_sio_data *sio_data) | 1546 | struct it87_sio_data *sio_data) |
1544 | { | 1547 | { |
1545 | int err = -ENODEV; | 1548 | int err; |
1546 | u16 chip_type; | 1549 | u16 chip_type; |
1547 | const char *board_vendor, *board_name; | 1550 | const char *board_vendor, *board_name; |
1548 | 1551 | ||
1549 | superio_enter(); | 1552 | err = superio_enter(); |
1553 | if (err) | ||
1554 | return err; | ||
1555 | |||
1556 | err = -ENODEV; | ||
1550 | chip_type = force_id ? force_id : superio_inw(DEVID); | 1557 | chip_type = force_id ? force_id : superio_inw(DEVID); |
1551 | 1558 | ||
1552 | switch (chip_type) { | 1559 | switch (chip_type) { |
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 934991237061..02cebb74e206 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c | |||
@@ -213,7 +213,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = { | |||
213 | 213 | ||
214 | /* This is the driver that will be inserted */ | 214 | /* This is the driver that will be inserted */ |
215 | static struct i2c_driver jc42_driver = { | 215 | static struct i2c_driver jc42_driver = { |
216 | .class = I2C_CLASS_HWMON, | 216 | .class = I2C_CLASS_SPD, |
217 | .driver = { | 217 | .driver = { |
218 | .name = "jc42", | 218 | .name = "jc42", |
219 | .pm = JC42_DEV_PM_OPS, | 219 | .pm = JC42_DEV_PM_OPS, |
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 82bf65aa2968..41aa6a319870 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring | 2 | * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de> | 4 | * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de> |
5 | * | 5 | * |
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
27 | 27 | ||
28 | MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor"); | 28 | MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor"); |
29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
30 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
31 | 31 | ||
@@ -173,7 +173,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev, | |||
173 | err = PTR_ERR(hwmon_dev); | 173 | err = PTR_ERR(hwmon_dev); |
174 | goto exit_remove; | 174 | goto exit_remove; |
175 | } | 175 | } |
176 | dev_set_drvdata(&pdev->dev, hwmon_dev); | 176 | pci_set_drvdata(pdev, hwmon_dev); |
177 | 177 | ||
178 | if (unreliable && force) | 178 | if (unreliable && force) |
179 | dev_warn(&pdev->dev, | 179 | dev_warn(&pdev->dev, |
@@ -194,7 +194,7 @@ exit: | |||
194 | 194 | ||
195 | static void __devexit k10temp_remove(struct pci_dev *pdev) | 195 | static void __devexit k10temp_remove(struct pci_dev *pdev) |
196 | { | 196 | { |
197 | hwmon_device_unregister(dev_get_drvdata(&pdev->dev)); | 197 | hwmon_device_unregister(pci_get_drvdata(pdev)); |
198 | device_remove_file(&pdev->dev, &dev_attr_name); | 198 | device_remove_file(&pdev->dev, &dev_attr_name); |
199 | device_remove_file(&pdev->dev, &dev_attr_temp1_input); | 199 | device_remove_file(&pdev->dev, &dev_attr_temp1_input); |
200 | device_remove_file(&pdev->dev, &dev_attr_temp1_max); | 200 | device_remove_file(&pdev->dev, &dev_attr_temp1_max); |
@@ -202,13 +202,14 @@ static void __devexit k10temp_remove(struct pci_dev *pdev) | |||
202 | &sensor_dev_attr_temp1_crit.dev_attr); | 202 | &sensor_dev_attr_temp1_crit.dev_attr); |
203 | device_remove_file(&pdev->dev, | 203 | device_remove_file(&pdev->dev, |
204 | &sensor_dev_attr_temp1_crit_hyst.dev_attr); | 204 | &sensor_dev_attr_temp1_crit_hyst.dev_attr); |
205 | dev_set_drvdata(&pdev->dev, NULL); | 205 | pci_set_drvdata(pdev, NULL); |
206 | } | 206 | } |
207 | 207 | ||
208 | static const struct pci_device_id k10temp_id_table[] = { | 208 | static const struct pci_device_id k10temp_id_table[] = { |
209 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, | 209 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, |
210 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, | 210 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, |
211 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, | 211 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, |
212 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, | ||
212 | {} | 213 | {} |
213 | }; | 214 | }; |
214 | MODULE_DEVICE_TABLE(pci, k10temp_id_table); | 215 | MODULE_DEVICE_TABLE(pci, k10temp_id_table); |
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 418496f13020..b923bc2307ad 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c | |||
@@ -252,7 +252,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, | |||
252 | 252 | ||
253 | data->name = "k8temp"; | 253 | data->name = "k8temp"; |
254 | mutex_init(&data->update_lock); | 254 | mutex_init(&data->update_lock); |
255 | dev_set_drvdata(&pdev->dev, data); | 255 | pci_set_drvdata(pdev, data); |
256 | 256 | ||
257 | /* Register sysfs hooks */ | 257 | /* Register sysfs hooks */ |
258 | err = device_create_file(&pdev->dev, | 258 | err = device_create_file(&pdev->dev, |
@@ -307,7 +307,7 @@ exit_remove: | |||
307 | &sensor_dev_attr_temp4_input.dev_attr); | 307 | &sensor_dev_attr_temp4_input.dev_attr); |
308 | device_remove_file(&pdev->dev, &dev_attr_name); | 308 | device_remove_file(&pdev->dev, &dev_attr_name); |
309 | exit_free: | 309 | exit_free: |
310 | dev_set_drvdata(&pdev->dev, NULL); | 310 | pci_set_drvdata(pdev, NULL); |
311 | kfree(data); | 311 | kfree(data); |
312 | exit: | 312 | exit: |
313 | return err; | 313 | return err; |
@@ -315,7 +315,7 @@ exit: | |||
315 | 315 | ||
316 | static void __devexit k8temp_remove(struct pci_dev *pdev) | 316 | static void __devexit k8temp_remove(struct pci_dev *pdev) |
317 | { | 317 | { |
318 | struct k8temp_data *data = dev_get_drvdata(&pdev->dev); | 318 | struct k8temp_data *data = pci_get_drvdata(pdev); |
319 | 319 | ||
320 | hwmon_device_unregister(data->hwmon_dev); | 320 | hwmon_device_unregister(data->hwmon_dev); |
321 | device_remove_file(&pdev->dev, | 321 | device_remove_file(&pdev->dev, |
@@ -327,7 +327,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev) | |||
327 | device_remove_file(&pdev->dev, | 327 | device_remove_file(&pdev->dev, |
328 | &sensor_dev_attr_temp4_input.dev_attr); | 328 | &sensor_dev_attr_temp4_input.dev_attr); |
329 | device_remove_file(&pdev->dev, &dev_attr_name); | 329 | device_remove_file(&pdev->dev, &dev_attr_name); |
330 | dev_set_drvdata(&pdev->dev, NULL); | 330 | pci_set_drvdata(pdev, NULL); |
331 | kfree(data); | 331 | kfree(data); |
332 | } | 332 | } |
333 | 333 | ||
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 3b84fb503053..c274ea25d899 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c | |||
@@ -58,7 +58,7 @@ static ssize_t lm70_sense_temp(struct device *dev, | |||
58 | int status, val = 0; | 58 | int status, val = 0; |
59 | u8 rxbuf[2]; | 59 | u8 rxbuf[2]; |
60 | s16 raw=0; | 60 | s16 raw=0; |
61 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | 61 | struct lm70 *p_lm70 = spi_get_drvdata(spi); |
62 | 62 | ||
63 | if (mutex_lock_interruptible(&p_lm70->lock)) | 63 | if (mutex_lock_interruptible(&p_lm70->lock)) |
64 | return -ERESTARTSYS; | 64 | return -ERESTARTSYS; |
@@ -163,7 +163,7 @@ static int __devinit lm70_probe(struct spi_device *spi) | |||
163 | status = PTR_ERR(p_lm70->hwmon_dev); | 163 | status = PTR_ERR(p_lm70->hwmon_dev); |
164 | goto out_dev_reg_failed; | 164 | goto out_dev_reg_failed; |
165 | } | 165 | } |
166 | dev_set_drvdata(&spi->dev, p_lm70); | 166 | spi_set_drvdata(spi, p_lm70); |
167 | 167 | ||
168 | if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input)) | 168 | if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input)) |
169 | || (status = device_create_file(&spi->dev, &dev_attr_name))) { | 169 | || (status = device_create_file(&spi->dev, &dev_attr_name))) { |
@@ -177,19 +177,19 @@ out_dev_create_file_failed: | |||
177 | device_remove_file(&spi->dev, &dev_attr_temp1_input); | 177 | device_remove_file(&spi->dev, &dev_attr_temp1_input); |
178 | hwmon_device_unregister(p_lm70->hwmon_dev); | 178 | hwmon_device_unregister(p_lm70->hwmon_dev); |
179 | out_dev_reg_failed: | 179 | out_dev_reg_failed: |
180 | dev_set_drvdata(&spi->dev, NULL); | 180 | spi_set_drvdata(spi, NULL); |
181 | kfree(p_lm70); | 181 | kfree(p_lm70); |
182 | return status; | 182 | return status; |
183 | } | 183 | } |
184 | 184 | ||
185 | static int __devexit lm70_remove(struct spi_device *spi) | 185 | static int __devexit lm70_remove(struct spi_device *spi) |
186 | { | 186 | { |
187 | struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); | 187 | struct lm70 *p_lm70 = spi_get_drvdata(spi); |
188 | 188 | ||
189 | device_remove_file(&spi->dev, &dev_attr_temp1_input); | 189 | device_remove_file(&spi->dev, &dev_attr_temp1_input); |
190 | device_remove_file(&spi->dev, &dev_attr_name); | 190 | device_remove_file(&spi->dev, &dev_attr_name); |
191 | hwmon_device_unregister(p_lm70->hwmon_dev); | 191 | hwmon_device_unregister(p_lm70->hwmon_dev); |
192 | dev_set_drvdata(&spi->dev, NULL); | 192 | spi_set_drvdata(spi, NULL); |
193 | kfree(p_lm70); | 193 | kfree(p_lm70); |
194 | 194 | ||
195 | return 0; | 195 | return 0; |
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 9a11532ecae8..ece3aafa54b3 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c | |||
@@ -41,13 +41,6 @@ | |||
41 | #include <linux/err.h> | 41 | #include <linux/err.h> |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * Addresses to scan. There are four disjoint possibilities, by pin config. | ||
45 | */ | ||
46 | |||
47 | static const unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, | ||
48 | I2C_CLIENT_END}; | ||
49 | |||
50 | /* | ||
51 | * Insmod parameters | 44 | * Insmod parameters |
52 | */ | 45 | */ |
53 | 46 | ||
@@ -114,8 +107,6 @@ module_param(clock, int, S_IRUGO); | |||
114 | 107 | ||
115 | static int max6650_probe(struct i2c_client *client, | 108 | static int max6650_probe(struct i2c_client *client, |
116 | const struct i2c_device_id *id); | 109 | const struct i2c_device_id *id); |
117 | static int max6650_detect(struct i2c_client *client, | ||
118 | struct i2c_board_info *info); | ||
119 | static int max6650_init_client(struct i2c_client *client); | 110 | static int max6650_init_client(struct i2c_client *client); |
120 | static int max6650_remove(struct i2c_client *client); | 111 | static int max6650_remove(struct i2c_client *client); |
121 | static struct max6650_data *max6650_update_device(struct device *dev); | 112 | static struct max6650_data *max6650_update_device(struct device *dev); |
@@ -125,21 +116,19 @@ static struct max6650_data *max6650_update_device(struct device *dev); | |||
125 | */ | 116 | */ |
126 | 117 | ||
127 | static const struct i2c_device_id max6650_id[] = { | 118 | static const struct i2c_device_id max6650_id[] = { |
128 | { "max6650", 0 }, | 119 | { "max6650", 1 }, |
120 | { "max6651", 4 }, | ||
129 | { } | 121 | { } |
130 | }; | 122 | }; |
131 | MODULE_DEVICE_TABLE(i2c, max6650_id); | 123 | MODULE_DEVICE_TABLE(i2c, max6650_id); |
132 | 124 | ||
133 | static struct i2c_driver max6650_driver = { | 125 | static struct i2c_driver max6650_driver = { |
134 | .class = I2C_CLASS_HWMON, | ||
135 | .driver = { | 126 | .driver = { |
136 | .name = "max6650", | 127 | .name = "max6650", |
137 | }, | 128 | }, |
138 | .probe = max6650_probe, | 129 | .probe = max6650_probe, |
139 | .remove = max6650_remove, | 130 | .remove = max6650_remove, |
140 | .id_table = max6650_id, | 131 | .id_table = max6650_id, |
141 | .detect = max6650_detect, | ||
142 | .address_list = normal_i2c, | ||
143 | }; | 132 | }; |
144 | 133 | ||
145 | /* | 134 | /* |
@@ -150,6 +139,7 @@ struct max6650_data | |||
150 | { | 139 | { |
151 | struct device *hwmon_dev; | 140 | struct device *hwmon_dev; |
152 | struct mutex update_lock; | 141 | struct mutex update_lock; |
142 | int nr_fans; | ||
153 | char valid; /* zero until following fields are valid */ | 143 | char valid; /* zero until following fields are valid */ |
154 | unsigned long last_updated; /* in jiffies */ | 144 | unsigned long last_updated; /* in jiffies */ |
155 | 145 | ||
@@ -501,9 +491,6 @@ static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, | |||
501 | 491 | ||
502 | static struct attribute *max6650_attrs[] = { | 492 | static struct attribute *max6650_attrs[] = { |
503 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 493 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
504 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
505 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
506 | &sensor_dev_attr_fan4_input.dev_attr.attr, | ||
507 | &dev_attr_fan1_target.attr, | 494 | &dev_attr_fan1_target.attr, |
508 | &dev_attr_fan1_div.attr, | 495 | &dev_attr_fan1_div.attr, |
509 | &dev_attr_pwm1_enable.attr, | 496 | &dev_attr_pwm1_enable.attr, |
@@ -521,42 +508,21 @@ static struct attribute_group max6650_attr_grp = { | |||
521 | .is_visible = max6650_attrs_visible, | 508 | .is_visible = max6650_attrs_visible, |
522 | }; | 509 | }; |
523 | 510 | ||
511 | static struct attribute *max6651_attrs[] = { | ||
512 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
513 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
514 | &sensor_dev_attr_fan4_input.dev_attr.attr, | ||
515 | NULL | ||
516 | }; | ||
517 | |||
518 | static const struct attribute_group max6651_attr_grp = { | ||
519 | .attrs = max6651_attrs, | ||
520 | }; | ||
521 | |||
524 | /* | 522 | /* |
525 | * Real code | 523 | * Real code |
526 | */ | 524 | */ |
527 | 525 | ||
528 | /* Return 0 if detection is successful, -ENODEV otherwise */ | ||
529 | static int max6650_detect(struct i2c_client *client, | ||
530 | struct i2c_board_info *info) | ||
531 | { | ||
532 | struct i2c_adapter *adapter = client->adapter; | ||
533 | int address = client->addr; | ||
534 | |||
535 | dev_dbg(&adapter->dev, "max6650_detect called\n"); | ||
536 | |||
537 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
538 | dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support " | ||
539 | "byte read mode, skipping.\n"); | ||
540 | return -ENODEV; | ||
541 | } | ||
542 | |||
543 | if (((i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0) | ||
544 | ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0) | ||
545 | ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0) | ||
546 | ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0) | ||
547 | ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) { | ||
548 | dev_dbg(&adapter->dev, | ||
549 | "max6650: detection failed at 0x%02x.\n", address); | ||
550 | return -ENODEV; | ||
551 | } | ||
552 | |||
553 | dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address); | ||
554 | |||
555 | strlcpy(info->type, "max6650", I2C_NAME_SIZE); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int max6650_probe(struct i2c_client *client, | 526 | static int max6650_probe(struct i2c_client *client, |
561 | const struct i2c_device_id *id) | 527 | const struct i2c_device_id *id) |
562 | { | 528 | { |
@@ -570,6 +536,7 @@ static int max6650_probe(struct i2c_client *client, | |||
570 | 536 | ||
571 | i2c_set_clientdata(client, data); | 537 | i2c_set_clientdata(client, data); |
572 | mutex_init(&data->update_lock); | 538 | mutex_init(&data->update_lock); |
539 | data->nr_fans = id->driver_data; | ||
573 | 540 | ||
574 | /* | 541 | /* |
575 | * Initialize the max6650 chip | 542 | * Initialize the max6650 chip |
@@ -581,6 +548,12 @@ static int max6650_probe(struct i2c_client *client, | |||
581 | err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp); | 548 | err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp); |
582 | if (err) | 549 | if (err) |
583 | goto err_free; | 550 | goto err_free; |
551 | /* 3 additional fan inputs for the MAX6651 */ | ||
552 | if (data->nr_fans == 4) { | ||
553 | err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp); | ||
554 | if (err) | ||
555 | goto err_remove; | ||
556 | } | ||
584 | 557 | ||
585 | data->hwmon_dev = hwmon_device_register(&client->dev); | 558 | data->hwmon_dev = hwmon_device_register(&client->dev); |
586 | if (!IS_ERR(data->hwmon_dev)) | 559 | if (!IS_ERR(data->hwmon_dev)) |
@@ -588,6 +561,9 @@ static int max6650_probe(struct i2c_client *client, | |||
588 | 561 | ||
589 | err = PTR_ERR(data->hwmon_dev); | 562 | err = PTR_ERR(data->hwmon_dev); |
590 | dev_err(&client->dev, "error registering hwmon device.\n"); | 563 | dev_err(&client->dev, "error registering hwmon device.\n"); |
564 | if (data->nr_fans == 4) | ||
565 | sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp); | ||
566 | err_remove: | ||
591 | sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); | 567 | sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); |
592 | err_free: | 568 | err_free: |
593 | kfree(data); | 569 | kfree(data); |
@@ -598,8 +574,10 @@ static int max6650_remove(struct i2c_client *client) | |||
598 | { | 574 | { |
599 | struct max6650_data *data = i2c_get_clientdata(client); | 575 | struct max6650_data *data = i2c_get_clientdata(client); |
600 | 576 | ||
601 | sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); | ||
602 | hwmon_device_unregister(data->hwmon_dev); | 577 | hwmon_device_unregister(data->hwmon_dev); |
578 | if (data->nr_fans == 4) | ||
579 | sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp); | ||
580 | sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); | ||
603 | kfree(data); | 581 | kfree(data); |
604 | return 0; | 582 | return 0; |
605 | } | 583 | } |
@@ -712,7 +690,7 @@ static struct max6650_data *max6650_update_device(struct device *dev) | |||
712 | MAX6650_REG_SPEED); | 690 | MAX6650_REG_SPEED); |
713 | data->config = i2c_smbus_read_byte_data(client, | 691 | data->config = i2c_smbus_read_byte_data(client, |
714 | MAX6650_REG_CONFIG); | 692 | MAX6650_REG_CONFIG); |
715 | for (i = 0; i < 4; i++) { | 693 | for (i = 0; i < data->nr_fans; i++) { |
716 | data->tach[i] = i2c_smbus_read_byte_data(client, | 694 | data->tach[i] = i2c_smbus_read_byte_data(client, |
717 | tach_reg[i]); | 695 | tach_reg[i]); |
718 | } | 696 | } |
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 9a51dcca9b0d..020c87273ea1 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c | |||
@@ -52,6 +52,9 @@ | |||
52 | #define SCH5627_COMPANY_ID 0x5c | 52 | #define SCH5627_COMPANY_ID 0x5c |
53 | #define SCH5627_PRIMARY_ID 0xa0 | 53 | #define SCH5627_PRIMARY_ID 0xa0 |
54 | 54 | ||
55 | #define SCH5627_CMD_READ 0x02 | ||
56 | #define SCH5627_CMD_WRITE 0x03 | ||
57 | |||
55 | #define SCH5627_REG_BUILD_CODE 0x39 | 58 | #define SCH5627_REG_BUILD_CODE 0x39 |
56 | #define SCH5627_REG_BUILD_ID 0x3a | 59 | #define SCH5627_REG_BUILD_ID 0x3a |
57 | #define SCH5627_REG_HWMON_ID 0x3c | 60 | #define SCH5627_REG_HWMON_ID 0x3c |
@@ -94,11 +97,13 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { | |||
94 | struct sch5627_data { | 97 | struct sch5627_data { |
95 | unsigned short addr; | 98 | unsigned short addr; |
96 | struct device *hwmon_dev; | 99 | struct device *hwmon_dev; |
100 | u8 control; | ||
97 | u8 temp_max[SCH5627_NO_TEMPS]; | 101 | u8 temp_max[SCH5627_NO_TEMPS]; |
98 | u8 temp_crit[SCH5627_NO_TEMPS]; | 102 | u8 temp_crit[SCH5627_NO_TEMPS]; |
99 | u16 fan_min[SCH5627_NO_FANS]; | 103 | u16 fan_min[SCH5627_NO_FANS]; |
100 | 104 | ||
101 | struct mutex update_lock; | 105 | struct mutex update_lock; |
106 | unsigned long last_battery; /* In jiffies */ | ||
102 | char valid; /* !=0 if following fields are valid */ | 107 | char valid; /* !=0 if following fields are valid */ |
103 | unsigned long last_updated; /* In jiffies */ | 108 | unsigned long last_updated; /* In jiffies */ |
104 | u16 temp[SCH5627_NO_TEMPS]; | 109 | u16 temp[SCH5627_NO_TEMPS]; |
@@ -140,7 +145,7 @@ static inline void superio_exit(int base) | |||
140 | release_region(base, 2); | 145 | release_region(base, 2); |
141 | } | 146 | } |
142 | 147 | ||
143 | static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) | 148 | static int sch5627_send_cmd(struct sch5627_data *data, u8 cmd, u16 reg, u8 v) |
144 | { | 149 | { |
145 | u8 val; | 150 | u8 val; |
146 | int i; | 151 | int i; |
@@ -163,10 +168,14 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) | |||
163 | outb(0x80, data->addr + 3); | 168 | outb(0x80, data->addr + 3); |
164 | 169 | ||
165 | /* Write Request Packet Header */ | 170 | /* Write Request Packet Header */ |
166 | outb(0x02, data->addr + 4); /* Access Type: VREG read */ | 171 | outb(cmd, data->addr + 4); /* VREG Access Type read:0x02 write:0x03 */ |
167 | outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */ | 172 | outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */ |
168 | outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */ | 173 | outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */ |
169 | 174 | ||
175 | /* Write Value field */ | ||
176 | if (cmd == SCH5627_CMD_WRITE) | ||
177 | outb(v, data->addr + 4); | ||
178 | |||
170 | /* Write Address field */ | 179 | /* Write Address field */ |
171 | outb(reg & 0xff, data->addr + 6); | 180 | outb(reg & 0xff, data->addr + 6); |
172 | outb(reg >> 8, data->addr + 7); | 181 | outb(reg >> 8, data->addr + 7); |
@@ -224,8 +233,22 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) | |||
224 | * But if we do that things don't work, so let's not. | 233 | * But if we do that things don't work, so let's not. |
225 | */ | 234 | */ |
226 | 235 | ||
227 | /* Read Data from Mailbox */ | 236 | /* Read Value field */ |
228 | return inb(data->addr + 4); | 237 | if (cmd == SCH5627_CMD_READ) |
238 | return inb(data->addr + 4); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) | ||
244 | { | ||
245 | return sch5627_send_cmd(data, SCH5627_CMD_READ, reg, 0); | ||
246 | } | ||
247 | |||
248 | static int sch5627_write_virtual_reg(struct sch5627_data *data, | ||
249 | u16 reg, u8 val) | ||
250 | { | ||
251 | return sch5627_send_cmd(data, SCH5627_CMD_WRITE, reg, val); | ||
229 | } | 252 | } |
230 | 253 | ||
231 | static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg) | 254 | static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg) |
@@ -272,6 +295,13 @@ static struct sch5627_data *sch5627_update_device(struct device *dev) | |||
272 | 295 | ||
273 | mutex_lock(&data->update_lock); | 296 | mutex_lock(&data->update_lock); |
274 | 297 | ||
298 | /* Trigger a Vbat voltage measurement every 5 minutes */ | ||
299 | if (time_after(jiffies, data->last_battery + 300 * HZ)) { | ||
300 | sch5627_write_virtual_reg(data, SCH5627_REG_CTRL, | ||
301 | data->control | 0x10); | ||
302 | data->last_battery = jiffies; | ||
303 | } | ||
304 | |||
275 | /* Cache the values for 1 second */ | 305 | /* Cache the values for 1 second */ |
276 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | 306 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
277 | for (i = 0; i < SCH5627_NO_TEMPS; i++) { | 307 | for (i = 0; i < SCH5627_NO_TEMPS; i++) { |
@@ -696,11 +726,17 @@ static int __devinit sch5627_probe(struct platform_device *pdev) | |||
696 | err = val; | 726 | err = val; |
697 | goto error; | 727 | goto error; |
698 | } | 728 | } |
699 | if (!(val & 0x01)) { | 729 | data->control = val; |
730 | if (!(data->control & 0x01)) { | ||
700 | pr_err("hardware monitoring not enabled\n"); | 731 | pr_err("hardware monitoring not enabled\n"); |
701 | err = -ENODEV; | 732 | err = -ENODEV; |
702 | goto error; | 733 | goto error; |
703 | } | 734 | } |
735 | /* Trigger a Vbat voltage measurement, so that we get a valid reading | ||
736 | the first time we read Vbat */ | ||
737 | sch5627_write_virtual_reg(data, SCH5627_REG_CTRL, | ||
738 | data->control | 0x10); | ||
739 | data->last_battery = jiffies; | ||
704 | 740 | ||
705 | /* | 741 | /* |
706 | * Read limits, we do this only once as reading a register on | 742 | * Read limits, we do this only once as reading a register on |
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 1f36c635d933..27a62711e0a6 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c | |||
@@ -258,7 +258,7 @@ static int __devinit env_probe(struct platform_device *op) | |||
258 | goto out_sysfs_remove_group; | 258 | goto out_sysfs_remove_group; |
259 | } | 259 | } |
260 | 260 | ||
261 | dev_set_drvdata(&op->dev, p); | 261 | platform_set_drvdata(op, p); |
262 | err = 0; | 262 | err = 0; |
263 | 263 | ||
264 | out: | 264 | out: |
@@ -277,7 +277,7 @@ out_free: | |||
277 | 277 | ||
278 | static int __devexit env_remove(struct platform_device *op) | 278 | static int __devexit env_remove(struct platform_device *op) |
279 | { | 279 | { |
280 | struct env *p = dev_get_drvdata(&op->dev); | 280 | struct env *p = platform_get_drvdata(op); |
281 | 281 | ||
282 | if (p) { | 282 | if (p) { |
283 | sysfs_remove_group(&op->dev.kobj, &env_group); | 283 | sysfs_remove_group(&op->dev.kobj, &env_group); |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index f1e3ff5880a9..a6c652ef516d 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -409,7 +409,7 @@ void i2c_unlock_adapter(struct i2c_adapter *); | |||
409 | /* i2c adapter classes (bitmask) */ | 409 | /* i2c adapter classes (bitmask) */ |
410 | #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ | 410 | #define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */ |
411 | #define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */ | 411 | #define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */ |
412 | #define I2C_CLASS_SPD (1<<7) /* SPD EEPROMs and similar */ | 412 | #define I2C_CLASS_SPD (1<<7) /* Memory modules */ |
413 | 413 | ||
414 | /* Internal numbers to terminate lists */ | 414 | /* Internal numbers to terminate lists */ |
415 | #define I2C_CLIENT_END 0xfffeU | 415 | #define I2C_CLIENT_END 0xfffeU |