aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig148
-rw-r--r--drivers/hwmon/Makefile10
-rw-r--r--drivers/hwmon/abituguru.c2
-rw-r--r--drivers/hwmon/abituguru3.c79
-rw-r--r--drivers/hwmon/applesmc.c2
-rw-r--r--drivers/hwmon/dme1737.c2
-rw-r--r--drivers/hwmon/f71805f.c2
-rw-r--r--drivers/hwmon/hdaps.c3
-rw-r--r--drivers/hwmon/hwmon-vid.c10
-rw-r--r--drivers/hwmon/it87.c2
-rw-r--r--drivers/hwmon/lm78.c2
-rw-r--r--drivers/hwmon/lm85.c32
-rw-r--r--drivers/hwmon/pc87360.c2
-rw-r--r--drivers/hwmon/pc87427.c8
-rw-r--r--drivers/hwmon/s3c-hwmon.c405
-rw-r--r--drivers/hwmon/sis5595.c2
-rw-r--r--drivers/hwmon/smsc47b397.c2
-rw-r--r--drivers/hwmon/smsc47m1.c2
-rw-r--r--drivers/hwmon/tmp421.c347
-rw-r--r--drivers/hwmon/via686a.c2
-rw-r--r--drivers/hwmon/vt1211.c8
-rw-r--r--drivers/hwmon/vt8231.c2
-rw-r--r--drivers/hwmon/w83627ehf.c2
-rw-r--r--drivers/hwmon/w83627hf.c2
-rw-r--r--drivers/hwmon/w83781d.c2
-rw-r--r--drivers/hwmon/wm831x-hwmon.c226
-rw-r--r--drivers/hwmon/wm8350-hwmon.c151
27 files changed, 1345 insertions, 112 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d5016691d40..ed7711d11ae8 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -28,6 +28,17 @@ config HWMON_VID
28 tristate 28 tristate
29 default n 29 default n
30 30
31config HWMON_DEBUG_CHIP
32 bool "Hardware Monitoring Chip debugging messages"
33 default n
34 help
35 Say Y here if you want the I2C chip drivers to produce a bunch of
36 debug messages to the system log. Select this if you are having
37 a problem with I2C support and want to see more of what is going
38 on.
39
40comment "Native drivers"
41
31config SENSORS_ABITUGURU 42config SENSORS_ABITUGURU
32 tristate "Abit uGuru (rev 1 & 2)" 43 tristate "Abit uGuru (rev 1 & 2)"
33 depends on X86 && EXPERIMENTAL 44 depends on X86 && EXPERIMENTAL
@@ -248,18 +259,6 @@ config SENSORS_ASB100
248 This driver can also be built as a module. If so, the module 259 This driver can also be built as a module. If so, the module
249 will be called asb100. 260 will be called asb100.
250 261
251config SENSORS_ATK0110
252 tristate "ASUS ATK0110 ACPI hwmon"
253 depends on X86 && ACPI && EXPERIMENTAL
254 help
255 If you say yes here you get support for the ACPI hardware
256 monitoring interface found in many ASUS motherboards. This
257 driver will provide readings of fans, voltages and temperatures
258 through the system firmware.
259
260 This driver can also be built as a module. If so, the module
261 will be called asus_atk0110.
262
263config SENSORS_ATXP1 262config SENSORS_ATXP1
264 tristate "Attansic ATXP1 VID controller" 263 tristate "Attansic ATXP1 VID controller"
265 depends on I2C && EXPERIMENTAL 264 depends on I2C && EXPERIMENTAL
@@ -702,6 +701,23 @@ config SENSORS_SHT15
702 This driver can also be built as a module. If so, the module 701 This driver can also be built as a module. If so, the module
703 will be called sht15. 702 will be called sht15.
704 703
704config SENSORS_S3C
705 tristate "S3C24XX/S3C64XX Inbuilt ADC"
706 depends on ARCH_S3C2410 || ARCH_S3C64XX
707 help
708 If you say yes here you get support for the on-board ADCs of
709 the Samsung S3C24XX or S3C64XX series of SoC
710
711 This driver can also be built as a module. If so, the module
712 will be called s3c-hwmo.
713
714config SENSORS_S3C_RAW
715 bool "Include raw channel attributes in sysfs"
716 depends on SENSORS_S3C
717 help
718 Say Y here if you want to include raw copies of all the ADC
719 channels in sysfs.
720
705config SENSORS_SIS5595 721config SENSORS_SIS5595
706 tristate "Silicon Integrated Systems Corp. SiS5595" 722 tristate "Silicon Integrated Systems Corp. SiS5595"
707 depends on PCI 723 depends on PCI
@@ -797,6 +813,16 @@ config SENSORS_TMP401
797 This driver can also be built as a module. If so, the module 813 This driver can also be built as a module. If so, the module
798 will be called tmp401. 814 will be called tmp401.
799 815
816config SENSORS_TMP421
817 tristate "Texas Instruments TMP421 and compatible"
818 depends on I2C && EXPERIMENTAL
819 help
820 If you say yes here you get support for Texas Instruments TMP421,
821 TMP422 and TMP423 temperature sensor chips.
822
823 This driver can also be built as a module. If so, the module
824 will be called tmp421.
825
800config SENSORS_VIA686A 826config SENSORS_VIA686A
801 tristate "VIA686A" 827 tristate "VIA686A"
802 depends on PCI 828 depends on PCI
@@ -920,6 +946,27 @@ config SENSORS_W83627EHF
920 This driver can also be built as a module. If so, the module 946 This driver can also be built as a module. If so, the module
921 will be called w83627ehf. 947 will be called w83627ehf.
922 948
949config SENSORS_WM831X
950 tristate "WM831x PMICs"
951 depends on MFD_WM831X
952 help
953 If you say yes here you get support for the hardware
954 monitoring functionality of the Wolfson Microelectronics
955 WM831x series of PMICs.
956
957 This driver can also be built as a module. If so, the module
958 will be called wm831x-hwmon.
959
960config SENSORS_WM8350
961 tristate "Wolfson Microelectronics WM835x"
962 depends on MFD_WM8350
963 help
964 If you say yes here you get support for the hardware
965 monitoring features of the WM835x series of PMICs.
966
967 This driver can also be built as a module. If so, the module
968 will be called wm8350-hwmon.
969
923config SENSORS_ULTRA45 970config SENSORS_ULTRA45
924 tristate "Sun Ultra45 PIC16F747" 971 tristate "Sun Ultra45 PIC16F747"
925 depends on SPARC64 972 depends on SPARC64
@@ -947,34 +994,6 @@ config SENSORS_HDAPS
947 Say Y here if you have an applicable laptop and want to experience 994 Say Y here if you have an applicable laptop and want to experience
948 the awesome power of hdaps. 995 the awesome power of hdaps.
949 996
950config SENSORS_LIS3LV02D
951 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
952 depends on ACPI && INPUT
953 select INPUT_POLLDEV
954 select NEW_LEDS
955 select LEDS_CLASS
956 default n
957 help
958 This driver provides support for the LIS3LV02Dx accelerometer. In
959 particular, it can be found in a number of HP laptops, which have the
960 "Mobile Data Protection System 3D" or "3D DriveGuard" feature. On such
961 systems the driver should load automatically (via ACPI). The
962 accelerometer might also be found in other systems, connected via SPI
963 or I2C. The accelerometer data is readable via
964 /sys/devices/platform/lis3lv02d.
965
966 This driver also provides an absolute input class device, allowing
967 the laptop to act as a pinball machine-esque joystick. On HP laptops,
968 if the led infrastructure is activated, support for a led indicating
969 disk protection will be provided as hp:red:hddprotection.
970
971 This driver can also be built as modules. If so, the core module
972 will be called lis3lv02d and a specific module for HP laptops will be
973 called hp_accel.
974
975 Say Y here if you have an applicable laptop and want to experience
976 the awesome power of lis3lv02d.
977
978config SENSORS_LIS3_SPI 997config SENSORS_LIS3_SPI
979 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" 998 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
980 depends on !ACPI && SPI_MASTER && INPUT 999 depends on !ACPI && SPI_MASTER && INPUT
@@ -1017,13 +1036,50 @@ config SENSORS_APPLESMC
1017 Say Y here if you have an applicable laptop and want to experience 1036 Say Y here if you have an applicable laptop and want to experience
1018 the awesome power of applesmc. 1037 the awesome power of applesmc.
1019 1038
1020config HWMON_DEBUG_CHIP 1039if ACPI
1021 bool "Hardware Monitoring Chip debugging messages" 1040
1041comment "ACPI drivers"
1042
1043config SENSORS_ATK0110
1044 tristate "ASUS ATK0110"
1045 depends on X86 && EXPERIMENTAL
1046 help
1047 If you say yes here you get support for the ACPI hardware
1048 monitoring interface found in many ASUS motherboards. This
1049 driver will provide readings of fans, voltages and temperatures
1050 through the system firmware.
1051
1052 This driver can also be built as a module. If so, the module
1053 will be called asus_atk0110.
1054
1055config SENSORS_LIS3LV02D
1056 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
1057 depends on INPUT
1058 select INPUT_POLLDEV
1059 select NEW_LEDS
1060 select LEDS_CLASS
1022 default n 1061 default n
1023 help 1062 help
1024 Say Y here if you want the I2C chip drivers to produce a bunch of 1063 This driver provides support for the LIS3LV02Dx accelerometer. In
1025 debug messages to the system log. Select this if you are having 1064 particular, it can be found in a number of HP laptops, which have the
1026 a problem with I2C support and want to see more of what is going 1065 "Mobile Data Protection System 3D" or "3D DriveGuard" feature. On such
1027 on. 1066 systems the driver should load automatically (via ACPI). The
1067 accelerometer might also be found in other systems, connected via SPI
1068 or I2C. The accelerometer data is readable via
1069 /sys/devices/platform/lis3lv02d.
1070
1071 This driver also provides an absolute input class device, allowing
1072 the laptop to act as a pinball machine-esque joystick. On HP laptops,
1073 if the led infrastructure is activated, support for a led indicating
1074 disk protection will be provided as hp:red:hddprotection.
1075
1076 This driver can also be built as modules. If so, the core module
1077 will be called lis3lv02d and a specific module for HP laptops will be
1078 called hp_accel.
1079
1080 Say Y here if you have an applicable laptop and want to experience
1081 the awesome power of lis3lv02d.
1082
1083endif # ACPI
1028 1084
1029endif # HWMON 1085endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce6bed5..bcf73a9bb619 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -5,6 +5,10 @@
5obj-$(CONFIG_HWMON) += hwmon.o 5obj-$(CONFIG_HWMON) += hwmon.o
6obj-$(CONFIG_HWMON_VID) += hwmon-vid.o 6obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
7 7
8# APCI drivers
9obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
10
11# Native drivers
8# asb100, then w83781d go first, as they can override other drivers' addresses. 12# asb100, then w83781d go first, as they can override other drivers' addresses.
9obj-$(CONFIG_SENSORS_ASB100) += asb100.o 13obj-$(CONFIG_SENSORS_ASB100) += asb100.o
10obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o 14obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
@@ -29,10 +33,8 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
29obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o 33obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
30obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o 34obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o
31obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o 35obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
32
33obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o 36obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
34obj-$(CONFIG_SENSORS_AMS) += ams/ 37obj-$(CONFIG_SENSORS_AMS) += ams/
35obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
36obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o 38obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
37obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o 39obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
38obj-$(CONFIG_SENSORS_DME1737) += dme1737.o 40obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
@@ -76,6 +78,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
76obj-$(CONFIG_SENSORS_PC87360) += pc87360.o 78obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
77obj-$(CONFIG_SENSORS_PC87427) += pc87427.o 79obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
78obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o 80obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
81obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
79obj-$(CONFIG_SENSORS_SHT15) += sht15.o 82obj-$(CONFIG_SENSORS_SHT15) += sht15.o
80obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o 83obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
81obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o 84obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
@@ -83,12 +86,15 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
83obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o 86obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
84obj-$(CONFIG_SENSORS_THMC50) += thmc50.o 87obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
85obj-$(CONFIG_SENSORS_TMP401) += tmp401.o 88obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
89obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
86obj-$(CONFIG_SENSORS_VIA686A) += via686a.o 90obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
87obj-$(CONFIG_SENSORS_VT1211) += vt1211.o 91obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
88obj-$(CONFIG_SENSORS_VT8231) += vt8231.o 92obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
89obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o 93obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
90obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o 94obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
91obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o 95obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
96obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
97obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
92 98
93ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) 99ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
94EXTRA_CFLAGS += -DDEBUG 100EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 4dbdb81ea3b1..03694cc17a32 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -32,7 +32,7 @@
32#include <linux/hwmon.h> 32#include <linux/hwmon.h>
33#include <linux/hwmon-sysfs.h> 33#include <linux/hwmon-sysfs.h>
34#include <linux/dmi.h> 34#include <linux/dmi.h>
35#include <asm/io.h> 35#include <linux/io.h>
36 36
37/* Banks */ 37/* Banks */
38#define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */ 38#define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 7d3f15d32fdf..3cf28af614b5 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -34,7 +34,7 @@
34#include <linux/hwmon.h> 34#include <linux/hwmon.h>
35#include <linux/hwmon-sysfs.h> 35#include <linux/hwmon-sysfs.h>
36#include <linux/dmi.h> 36#include <linux/dmi.h>
37#include <asm/io.h> 37#include <linux/io.h>
38 38
39/* uGuru3 bank addresses */ 39/* uGuru3 bank addresses */
40#define ABIT_UGURU3_SETTINGS_BANK 0x01 40#define ABIT_UGURU3_SETTINGS_BANK 0x01
@@ -117,9 +117,12 @@ struct abituguru3_sensor_info {
117 int offset; 117 int offset;
118}; 118};
119 119
120/* Avoid use of flexible array members */
121#define ABIT_UGURU3_MAX_DMI_NAMES 2
122
120struct abituguru3_motherboard_info { 123struct abituguru3_motherboard_info {
121 u16 id; 124 u16 id;
122 const char *dmi_name; 125 const char *dmi_name[ABIT_UGURU3_MAX_DMI_NAMES + 1];
123 /* + 1 -> end of sensors indicated by a sensor with name == NULL */ 126 /* + 1 -> end of sensors indicated by a sensor with name == NULL */
124 struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1]; 127 struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
125}; 128};
@@ -164,7 +167,7 @@ struct abituguru3_data {
164 167
165/* Constants */ 168/* Constants */
166static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { 169static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
167 { 0x000C, NULL /* Unknown, need DMI string */, { 170 { 0x000C, { NULL } /* Unknown, need DMI string */, {
168 { "CPU Core", 0, 0, 10, 1, 0 }, 171 { "CPU Core", 0, 0, 10, 1, 0 },
169 { "DDR", 1, 0, 10, 1, 0 }, 172 { "DDR", 1, 0, 10, 1, 0 },
170 { "DDR VTT", 2, 0, 10, 1, 0 }, 173 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -186,7 +189,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
186 { "AUX1 Fan", 35, 2, 60, 1, 0 }, 189 { "AUX1 Fan", 35, 2, 60, 1, 0 },
187 { NULL, 0, 0, 0, 0, 0 } } 190 { NULL, 0, 0, 0, 0, 0 } }
188 }, 191 },
189 { 0x000D, NULL /* Abit AW8, need DMI string */, { 192 { 0x000D, { NULL } /* Abit AW8, need DMI string */, {
190 { "CPU Core", 0, 0, 10, 1, 0 }, 193 { "CPU Core", 0, 0, 10, 1, 0 },
191 { "DDR", 1, 0, 10, 1, 0 }, 194 { "DDR", 1, 0, 10, 1, 0 },
192 { "DDR VTT", 2, 0, 10, 1, 0 }, 195 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -215,7 +218,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
215 { "AUX5 Fan", 39, 2, 60, 1, 0 }, 218 { "AUX5 Fan", 39, 2, 60, 1, 0 },
216 { NULL, 0, 0, 0, 0, 0 } } 219 { NULL, 0, 0, 0, 0, 0 } }
217 }, 220 },
218 { 0x000E, NULL /* AL-8, need DMI string */, { 221 { 0x000E, { NULL } /* AL-8, need DMI string */, {
219 { "CPU Core", 0, 0, 10, 1, 0 }, 222 { "CPU Core", 0, 0, 10, 1, 0 },
220 { "DDR", 1, 0, 10, 1, 0 }, 223 { "DDR", 1, 0, 10, 1, 0 },
221 { "DDR VTT", 2, 0, 10, 1, 0 }, 224 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -236,7 +239,8 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
236 { "SYS Fan", 34, 2, 60, 1, 0 }, 239 { "SYS Fan", 34, 2, 60, 1, 0 },
237 { NULL, 0, 0, 0, 0, 0 } } 240 { NULL, 0, 0, 0, 0, 0 } }
238 }, 241 },
239 { 0x000F, NULL /* Unknown, need DMI string */, { 242 { 0x000F, { NULL } /* Unknown, need DMI string */, {
243
240 { "CPU Core", 0, 0, 10, 1, 0 }, 244 { "CPU Core", 0, 0, 10, 1, 0 },
241 { "DDR", 1, 0, 10, 1, 0 }, 245 { "DDR", 1, 0, 10, 1, 0 },
242 { "DDR VTT", 2, 0, 10, 1, 0 }, 246 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -257,7 +261,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
257 { "SYS Fan", 34, 2, 60, 1, 0 }, 261 { "SYS Fan", 34, 2, 60, 1, 0 },
258 { NULL, 0, 0, 0, 0, 0 } } 262 { NULL, 0, 0, 0, 0, 0 } }
259 }, 263 },
260 { 0x0010, NULL /* Abit NI8 SLI GR, need DMI string */, { 264 { 0x0010, { NULL } /* Abit NI8 SLI GR, need DMI string */, {
261 { "CPU Core", 0, 0, 10, 1, 0 }, 265 { "CPU Core", 0, 0, 10, 1, 0 },
262 { "DDR", 1, 0, 10, 1, 0 }, 266 { "DDR", 1, 0, 10, 1, 0 },
263 { "DDR VTT", 2, 0, 10, 1, 0 }, 267 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -279,7 +283,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
279 { "OTES1 Fan", 36, 2, 60, 1, 0 }, 283 { "OTES1 Fan", 36, 2, 60, 1, 0 },
280 { NULL, 0, 0, 0, 0, 0 } } 284 { NULL, 0, 0, 0, 0, 0 } }
281 }, 285 },
282 { 0x0011, "AT8 32X", { 286 { 0x0011, { "AT8 32X", NULL }, {
283 { "CPU Core", 0, 0, 10, 1, 0 }, 287 { "CPU Core", 0, 0, 10, 1, 0 },
284 { "DDR", 1, 0, 20, 1, 0 }, 288 { "DDR", 1, 0, 20, 1, 0 },
285 { "DDR VTT", 2, 0, 10, 1, 0 }, 289 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -306,7 +310,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
306 { "AUX3 Fan", 37, 2, 60, 1, 0 }, 310 { "AUX3 Fan", 37, 2, 60, 1, 0 },
307 { NULL, 0, 0, 0, 0, 0 } } 311 { NULL, 0, 0, 0, 0, 0 } }
308 }, 312 },
309 { 0x0012, NULL /* Abit AN8 32X, need DMI string */, { 313 { 0x0012, { NULL } /* Abit AN8 32X, need DMI string */, {
310 { "CPU Core", 0, 0, 10, 1, 0 }, 314 { "CPU Core", 0, 0, 10, 1, 0 },
311 { "DDR", 1, 0, 20, 1, 0 }, 315 { "DDR", 1, 0, 20, 1, 0 },
312 { "DDR VTT", 2, 0, 10, 1, 0 }, 316 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -328,7 +332,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
328 { "AUX1 Fan", 36, 2, 60, 1, 0 }, 332 { "AUX1 Fan", 36, 2, 60, 1, 0 },
329 { NULL, 0, 0, 0, 0, 0 } } 333 { NULL, 0, 0, 0, 0, 0 } }
330 }, 334 },
331 { 0x0013, NULL /* Abit AW8D, need DMI string */, { 335 { 0x0013, { NULL } /* Abit AW8D, need DMI string */, {
332 { "CPU Core", 0, 0, 10, 1, 0 }, 336 { "CPU Core", 0, 0, 10, 1, 0 },
333 { "DDR", 1, 0, 10, 1, 0 }, 337 { "DDR", 1, 0, 10, 1, 0 },
334 { "DDR VTT", 2, 0, 10, 1, 0 }, 338 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -357,7 +361,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
357 { "AUX5 Fan", 39, 2, 60, 1, 0 }, 361 { "AUX5 Fan", 39, 2, 60, 1, 0 },
358 { NULL, 0, 0, 0, 0, 0 } } 362 { NULL, 0, 0, 0, 0, 0 } }
359 }, 363 },
360 { 0x0014, "AB9", /* + AB9 Pro */ { 364 { 0x0014, { "AB9", "AB9 Pro", NULL }, {
361 { "CPU Core", 0, 0, 10, 1, 0 }, 365 { "CPU Core", 0, 0, 10, 1, 0 },
362 { "DDR", 1, 0, 10, 1, 0 }, 366 { "DDR", 1, 0, 10, 1, 0 },
363 { "DDR VTT", 2, 0, 10, 1, 0 }, 367 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -378,7 +382,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
378 { "SYS Fan", 34, 2, 60, 1, 0 }, 382 { "SYS Fan", 34, 2, 60, 1, 0 },
379 { NULL, 0, 0, 0, 0, 0 } } 383 { NULL, 0, 0, 0, 0, 0 } }
380 }, 384 },
381 { 0x0015, NULL /* Unknown, need DMI string */, { 385 { 0x0015, { NULL } /* Unknown, need DMI string */, {
382 { "CPU Core", 0, 0, 10, 1, 0 }, 386 { "CPU Core", 0, 0, 10, 1, 0 },
383 { "DDR", 1, 0, 20, 1, 0 }, 387 { "DDR", 1, 0, 20, 1, 0 },
384 { "DDR VTT", 2, 0, 10, 1, 0 }, 388 { "DDR VTT", 2, 0, 10, 1, 0 },
@@ -402,7 +406,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
402 { "AUX3 Fan", 36, 2, 60, 1, 0 }, 406 { "AUX3 Fan", 36, 2, 60, 1, 0 },
403 { NULL, 0, 0, 0, 0, 0 } } 407 { NULL, 0, 0, 0, 0, 0 } }
404 }, 408 },
405 { 0x0016, "AW9D-MAX", { 409 { 0x0016, { "AW9D-MAX", NULL }, {
406 { "CPU Core", 0, 0, 10, 1, 0 }, 410 { "CPU Core", 0, 0, 10, 1, 0 },
407 { "DDR2", 1, 0, 20, 1, 0 }, 411 { "DDR2", 1, 0, 20, 1, 0 },
408 { "DDR2 VTT", 2, 0, 10, 1, 0 }, 412 { "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -430,7 +434,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
430 { "OTES1 Fan", 38, 2, 60, 1, 0 }, 434 { "OTES1 Fan", 38, 2, 60, 1, 0 },
431 { NULL, 0, 0, 0, 0, 0 } } 435 { NULL, 0, 0, 0, 0, 0 } }
432 }, 436 },
433 { 0x0017, NULL /* Unknown, need DMI string */, { 437 { 0x0017, { NULL } /* Unknown, need DMI string */, {
434 { "CPU Core", 0, 0, 10, 1, 0 }, 438 { "CPU Core", 0, 0, 10, 1, 0 },
435 { "DDR2", 1, 0, 20, 1, 0 }, 439 { "DDR2", 1, 0, 20, 1, 0 },
436 { "DDR2 VTT", 2, 0, 10, 1, 0 }, 440 { "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -455,7 +459,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
455 { "AUX3 FAN", 37, 2, 60, 1, 0 }, 459 { "AUX3 FAN", 37, 2, 60, 1, 0 },
456 { NULL, 0, 0, 0, 0, 0 } } 460 { NULL, 0, 0, 0, 0, 0 } }
457 }, 461 },
458 { 0x0018, "AB9 QuadGT", { 462 { 0x0018, { "AB9 QuadGT", NULL }, {
459 { "CPU Core", 0, 0, 10, 1, 0 }, 463 { "CPU Core", 0, 0, 10, 1, 0 },
460 { "DDR2", 1, 0, 20, 1, 0 }, 464 { "DDR2", 1, 0, 20, 1, 0 },
461 { "DDR2 VTT", 2, 0, 10, 1, 0 }, 465 { "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -482,7 +486,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
482 { "AUX3 Fan", 36, 2, 60, 1, 0 }, 486 { "AUX3 Fan", 36, 2, 60, 1, 0 },
483 { NULL, 0, 0, 0, 0, 0 } } 487 { NULL, 0, 0, 0, 0, 0 } }
484 }, 488 },
485 { 0x0019, "IN9 32X MAX", { 489 { 0x0019, { "IN9 32X MAX", NULL }, {
486 { "CPU Core", 7, 0, 10, 1, 0 }, 490 { "CPU Core", 7, 0, 10, 1, 0 },
487 { "DDR2", 13, 0, 20, 1, 0 }, 491 { "DDR2", 13, 0, 20, 1, 0 },
488 { "DDR2 VTT", 14, 0, 10, 1, 0 }, 492 { "DDR2 VTT", 14, 0, 10, 1, 0 },
@@ -509,7 +513,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
509 { "AUX3 FAN", 36, 2, 60, 1, 0 }, 513 { "AUX3 FAN", 36, 2, 60, 1, 0 },
510 { NULL, 0, 0, 0, 0, 0 } } 514 { NULL, 0, 0, 0, 0, 0 } }
511 }, 515 },
512 { 0x001A, "IP35 Pro", { 516 { 0x001A, { "IP35 Pro", "IP35 Pro XE", NULL }, {
513 { "CPU Core", 0, 0, 10, 1, 0 }, 517 { "CPU Core", 0, 0, 10, 1, 0 },
514 { "DDR2", 1, 0, 20, 1, 0 }, 518 { "DDR2", 1, 0, 20, 1, 0 },
515 { "DDR2 VTT", 2, 0, 10, 1, 0 }, 519 { "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -537,7 +541,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
537 { "AUX4 Fan", 37, 2, 60, 1, 0 }, 541 { "AUX4 Fan", 37, 2, 60, 1, 0 },
538 { NULL, 0, 0, 0, 0, 0 } } 542 { NULL, 0, 0, 0, 0, 0 } }
539 }, 543 },
540 { 0x001B, NULL /* Unknown, need DMI string */, { 544 { 0x001B, { NULL } /* Unknown, need DMI string */, {
541 { "CPU Core", 0, 0, 10, 1, 0 }, 545 { "CPU Core", 0, 0, 10, 1, 0 },
542 { "DDR3", 1, 0, 20, 1, 0 }, 546 { "DDR3", 1, 0, 20, 1, 0 },
543 { "DDR3 VTT", 2, 0, 10, 1, 0 }, 547 { "DDR3 VTT", 2, 0, 10, 1, 0 },
@@ -564,7 +568,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
564 { "AUX3 Fan", 36, 2, 60, 1, 0 }, 568 { "AUX3 Fan", 36, 2, 60, 1, 0 },
565 { NULL, 0, 0, 0, 0, 0 } } 569 { NULL, 0, 0, 0, 0, 0 } }
566 }, 570 },
567 { 0x001C, "IX38 QuadGT", { 571 { 0x001C, { "IX38 QuadGT", NULL }, {
568 { "CPU Core", 0, 0, 10, 1, 0 }, 572 { "CPU Core", 0, 0, 10, 1, 0 },
569 { "DDR2", 1, 0, 20, 1, 0 }, 573 { "DDR2", 1, 0, 20, 1, 0 },
570 { "DDR2 VTT", 2, 0, 10, 1, 0 }, 574 { "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -591,7 +595,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
591 { "AUX3 Fan", 36, 2, 60, 1, 0 }, 595 { "AUX3 Fan", 36, 2, 60, 1, 0 },
592 { NULL, 0, 0, 0, 0, 0 } } 596 { NULL, 0, 0, 0, 0, 0 } }
593 }, 597 },
594 { 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } } 598 { 0x0000, { NULL }, { { NULL, 0, 0, 0, 0, 0 } } }
595}; 599};
596 600
597 601
@@ -946,15 +950,6 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
946 printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard " 950 printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
947 "ID: %04X\n", (unsigned int)id); 951 "ID: %04X\n", (unsigned int)id);
948 952
949#ifdef CONFIG_DMI
950 if (!abituguru3_motherboards[i].dmi_name) {
951 printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was "
952 "not detected using DMI. Please send the output of "
953 "\"dmidecode\" to the abituguru3 maintainer "
954 "(see MAINTAINERS)\n");
955 }
956#endif
957
958 /* Fill the sysfs attr array */ 953 /* Fill the sysfs attr array */
959 sysfs_attr_i = 0; 954 sysfs_attr_i = 0;
960 sysfs_filename = data->sysfs_names; 955 sysfs_filename = data->sysfs_names;
@@ -1131,6 +1126,7 @@ static int __init abituguru3_dmi_detect(void)
1131{ 1126{
1132 const char *board_vendor, *board_name; 1127 const char *board_vendor, *board_name;
1133 int i, err = (force) ? 1 : -ENODEV; 1128 int i, err = (force) ? 1 : -ENODEV;
1129 const char *const *dmi_name;
1134 size_t sublen; 1130 size_t sublen;
1135 1131
1136 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 1132 board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
@@ -1151,17 +1147,17 @@ static int __init abituguru3_dmi_detect(void)
1151 sublen--; 1147 sublen--;
1152 1148
1153 for (i = 0; abituguru3_motherboards[i].id; i++) { 1149 for (i = 0; abituguru3_motherboards[i].id; i++) {
1154 const char *dmi_name = abituguru3_motherboards[i].dmi_name; 1150 dmi_name = abituguru3_motherboards[i].dmi_name;
1155 if (!dmi_name || strlen(dmi_name) != sublen) 1151 for ( ; *dmi_name; dmi_name++) {
1156 continue; 1152 if (strlen(*dmi_name) != sublen)
1157 if (!strncasecmp(board_name, dmi_name, sublen)) 1153 continue;
1158 break; 1154 if (!strncasecmp(board_name, *dmi_name, sublen))
1155 return 0;
1156 }
1159 } 1157 }
1160 1158
1161 if (!abituguru3_motherboards[i].id) 1159 /* No match found */
1162 return 1; 1160 return 1;
1163
1164 return 0;
1165} 1161}
1166 1162
1167#else /* !CONFIG_DMI */ 1163#else /* !CONFIG_DMI */
@@ -1221,6 +1217,13 @@ static int __init abituguru3_init(void)
1221 err = abituguru3_detect(); 1217 err = abituguru3_detect();
1222 if (err) 1218 if (err)
1223 return err; 1219 return err;
1220
1221#ifdef CONFIG_DMI
1222 printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was "
1223 "not detected using DMI. Please send the output of "
1224 "\"dmidecode\" to the abituguru3 maintainer "
1225 "(see MAINTAINERS)\n");
1226#endif
1224 } 1227 }
1225 1228
1226 err = platform_driver_register(&abituguru3_driver); 1229 err = platform_driver_register(&abituguru3_driver);
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 678e34b01e52..753b34885f9d 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -35,7 +35,7 @@
35#include <linux/dmi.h> 35#include <linux/dmi.h>
36#include <linux/mutex.h> 36#include <linux/mutex.h>
37#include <linux/hwmon-sysfs.h> 37#include <linux/hwmon-sysfs.h>
38#include <asm/io.h> 38#include <linux/io.h>
39#include <linux/leds.h> 39#include <linux/leds.h>
40#include <linux/hwmon.h> 40#include <linux/hwmon.h>
41#include <linux/workqueue.h> 41#include <linux/workqueue.h>
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 3df202a9ad72..9814d51b3af4 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -35,7 +35,7 @@
35#include <linux/err.h> 35#include <linux/err.h>
36#include <linux/mutex.h> 36#include <linux/mutex.h>
37#include <linux/acpi.h> 37#include <linux/acpi.h>
38#include <asm/io.h> 38#include <linux/io.h>
39 39
40/* ISA device, if found */ 40/* ISA device, if found */
41static struct platform_device *pdev; 41static struct platform_device *pdev;
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 899876579253..525a00bd70b1 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -40,7 +40,7 @@
40#include <linux/sysfs.h> 40#include <linux/sysfs.h>
41#include <linux/ioport.h> 41#include <linux/ioport.h>
42#include <linux/acpi.h> 42#include <linux/acpi.h>
43#include <asm/io.h> 43#include <linux/io.h>
44 44
45static unsigned short force_id; 45static unsigned short force_id;
46module_param(force_id, ushort, 0); 46module_param(force_id, ushort, 0);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index d3612a1f1981..be2d131e405c 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -35,8 +35,7 @@
35#include <linux/timer.h> 35#include <linux/timer.h>
36#include <linux/dmi.h> 36#include <linux/dmi.h>
37#include <linux/jiffies.h> 37#include <linux/jiffies.h>
38 38#include <linux/io.h>
39#include <asm/io.h>
40 39
41#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ 40#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */
42#define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */ 41#define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index bfc296145bba..bf0862a803c0 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -179,8 +179,14 @@ struct vrm_model {
179static struct vrm_model vrm_models[] = { 179static struct vrm_model vrm_models[] = {
180 {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ 180 {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */
181 {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ 181 {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */
182 {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* NPT family 0Fh */ 182 /* In theory, all NPT family 0Fh processors have 6 VID pins and should
183 thus use vrm 25, however in practice not all mainboards route the
184 6th VID pin because it is never needed. So we use the 5 VID pin
185 variant (vrm 24) for the models which exist today. */
186 {X86_VENDOR_AMD, 0xF, 0x7F, ANY, 24}, /* NPT family 0Fh */
187 {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* future fam. 0Fh */
183 {X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */ 188 {X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */
189
184 {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ 190 {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */
185 {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ 191 {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */
186 {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ 192 {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */
@@ -191,12 +197,14 @@ static struct vrm_model vrm_models[] = {
191 {X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */ 197 {X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */
192 {X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */ 198 {X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */
193 {X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */ 199 {X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */
200
194 {X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */ 201 {X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
195 {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */ 202 {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
196 {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */ 203 {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */
197 {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */ 204 {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
198 {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */ 205 {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
199 {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */ 206 {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */
207
200 {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */ 208 {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */
201}; 209};
202 210
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 9157247fed8e..ffeb2a10e1a7 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -50,7 +50,7 @@
50#include <linux/string.h> 50#include <linux/string.h>
51#include <linux/dmi.h> 51#include <linux/dmi.h>
52#include <linux/acpi.h> 52#include <linux/acpi.h>
53#include <asm/io.h> 53#include <linux/io.h>
54 54
55#define DRVNAME "it87" 55#define DRVNAME "it87"
56 56
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index a1787fdf5b9f..f7e70163e016 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -31,7 +31,7 @@
31#include <linux/hwmon-sysfs.h> 31#include <linux/hwmon-sysfs.h>
32#include <linux/err.h> 32#include <linux/err.h>
33#include <linux/mutex.h> 33#include <linux/mutex.h>
34#include <asm/io.h> 34#include <linux/io.h>
35 35
36/* ISA device, if found */ 36/* ISA device, if found */
37static struct platform_device *pdev; 37static struct platform_device *pdev;
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index b251d8674b41..6c53d987de10 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -75,6 +75,8 @@ I2C_CLIENT_INSMOD_7(lm85b, lm85c, adm1027, adt7463, adt7468, emc6d100,
75#define LM85_VERSTEP_GENERIC2 0x70 75#define LM85_VERSTEP_GENERIC2 0x70
76#define LM85_VERSTEP_LM85C 0x60 76#define LM85_VERSTEP_LM85C 0x60
77#define LM85_VERSTEP_LM85B 0x62 77#define LM85_VERSTEP_LM85B 0x62
78#define LM85_VERSTEP_LM96000_1 0x68
79#define LM85_VERSTEP_LM96000_2 0x69
78#define LM85_VERSTEP_ADM1027 0x60 80#define LM85_VERSTEP_ADM1027 0x60
79#define LM85_VERSTEP_ADT7463 0x62 81#define LM85_VERSTEP_ADT7463 0x62
80#define LM85_VERSTEP_ADT7463C 0x6A 82#define LM85_VERSTEP_ADT7463C 0x6A
@@ -1133,6 +1135,26 @@ static void lm85_init_client(struct i2c_client *client)
1133 dev_warn(&client->dev, "Device is not ready\n"); 1135 dev_warn(&client->dev, "Device is not ready\n");
1134} 1136}
1135 1137
1138static int lm85_is_fake(struct i2c_client *client)
1139{
1140 /*
1141 * Differenciate between real LM96000 and Winbond WPCD377I. The latter
1142 * emulate the former except that it has no hardware monitoring function
1143 * so the readings are always 0.
1144 */
1145 int i;
1146 u8 in_temp, fan;
1147
1148 for (i = 0; i < 8; i++) {
1149 in_temp = i2c_smbus_read_byte_data(client, 0x20 + i);
1150 fan = i2c_smbus_read_byte_data(client, 0x28 + i);
1151 if (in_temp != 0x00 || fan != 0xff)
1152 return 0;
1153 }
1154
1155 return 1;
1156}
1157
1136/* Return 0 if detection is successful, -ENODEV otherwise */ 1158/* Return 0 if detection is successful, -ENODEV otherwise */
1137static int lm85_detect(struct i2c_client *client, int kind, 1159static int lm85_detect(struct i2c_client *client, int kind,
1138 struct i2c_board_info *info) 1160 struct i2c_board_info *info)
@@ -1173,6 +1195,16 @@ static int lm85_detect(struct i2c_client *client, int kind,
1173 case LM85_VERSTEP_LM85B: 1195 case LM85_VERSTEP_LM85B:
1174 kind = lm85b; 1196 kind = lm85b;
1175 break; 1197 break;
1198 case LM85_VERSTEP_LM96000_1:
1199 case LM85_VERSTEP_LM96000_2:
1200 /* Check for Winbond WPCD377I */
1201 if (lm85_is_fake(client)) {
1202 dev_dbg(&adapter->dev,
1203 "Found Winbond WPCD377I, "
1204 "ignoring\n");
1205 return -ENODEV;
1206 }
1207 break;
1176 } 1208 }
1177 } else if (company == LM85_COMPANY_ANALOG_DEV) { 1209 } else if (company == LM85_COMPANY_ANALOG_DEV) {
1178 switch (verstep) { 1210 switch (verstep) {
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index fb052fea3744..4a64b85d4ec9 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -44,7 +44,7 @@
44#include <linux/err.h> 44#include <linux/err.h>
45#include <linux/mutex.h> 45#include <linux/mutex.h>
46#include <linux/acpi.h> 46#include <linux/acpi.h>
47#include <asm/io.h> 47#include <linux/io.h>
48 48
49static u8 devid; 49static u8 devid;
50static struct platform_device *pdev; 50static struct platform_device *pdev;
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 3a8a0f7a7736..3170b26d2443 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -33,7 +33,7 @@
33#include <linux/sysfs.h> 33#include <linux/sysfs.h>
34#include <linux/ioport.h> 34#include <linux/ioport.h>
35#include <linux/acpi.h> 35#include <linux/acpi.h>
36#include <asm/io.h> 36#include <linux/io.h>
37 37
38static unsigned short force_id; 38static unsigned short force_id;
39module_param(force_id, ushort, 0); 39module_param(force_id, ushort, 0);
@@ -435,7 +435,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
435 /* This will need to be revisited when we add support for 435 /* This will need to be revisited when we add support for
436 temperature and voltage monitoring. */ 436 temperature and voltage monitoring. */
437 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 437 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
438 if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { 438 if (!request_region(res->start, resource_size(res), DRVNAME)) {
439 err = -EBUSY; 439 err = -EBUSY;
440 dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", 440 dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
441 (unsigned long)res->start, (unsigned long)res->end); 441 (unsigned long)res->start, (unsigned long)res->end);
@@ -475,7 +475,7 @@ exit_remove_files:
475 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); 475 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
476 } 476 }
477exit_release_region: 477exit_release_region:
478 release_region(res->start, res->end - res->start + 1); 478 release_region(res->start, resource_size(res));
479exit_kfree: 479exit_kfree:
480 platform_set_drvdata(pdev, NULL); 480 platform_set_drvdata(pdev, NULL);
481 kfree(data); 481 kfree(data);
@@ -500,7 +500,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
500 kfree(data); 500 kfree(data);
501 501
502 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 502 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
503 release_region(res->start, res->end - res->start + 1); 503 release_region(res->start, resource_size(res));
504 504
505 return 0; 505 return 0;
506} 506}
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
new file mode 100644
index 000000000000..3a524f2fe493
--- /dev/null
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -0,0 +1,405 @@
1/* linux/drivers/hwmon/s3c-hwmon.c
2 *
3 * Copyright (C) 2005, 2008, 2009 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX/S3C64XX ADC hwmon support
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/delay.h>
26#include <linux/io.h>
27#include <linux/init.h>
28#include <linux/err.h>
29#include <linux/clk.h>
30#include <linux/interrupt.h>
31#include <linux/platform_device.h>
32
33#include <linux/hwmon.h>
34#include <linux/hwmon-sysfs.h>
35
36#include <plat/adc.h>
37#include <plat/hwmon.h>
38
39struct s3c_hwmon_attr {
40 struct sensor_device_attribute in;
41 struct sensor_device_attribute label;
42 char in_name[12];
43 char label_name[12];
44};
45
46/**
47 * struct s3c_hwmon - ADC hwmon client information
48 * @lock: Access lock to serialise the conversions.
49 * @client: The client we registered with the S3C ADC core.
50 * @hwmon_dev: The hwmon device we created.
51 * @attr: The holders for the channel attributes.
52*/
53struct s3c_hwmon {
54 struct semaphore lock;
55 struct s3c_adc_client *client;
56 struct device *hwmon_dev;
57
58 struct s3c_hwmon_attr attrs[8];
59};
60
61/**
62 * s3c_hwmon_read_ch - read a value from a given adc channel.
63 * @dev: The device.
64 * @hwmon: Our state.
65 * @channel: The channel we're reading from.
66 *
67 * Read a value from the @channel with the proper locking and sleep until
68 * either the read completes or we timeout awaiting the ADC core to get
69 * back to us.
70 */
71static int s3c_hwmon_read_ch(struct device *dev,
72 struct s3c_hwmon *hwmon, int channel)
73{
74 int ret;
75
76 ret = down_interruptible(&hwmon->lock);
77 if (ret < 0)
78 return ret;
79
80 dev_dbg(dev, "reading channel %d\n", channel);
81
82 ret = s3c_adc_read(hwmon->client, channel);
83 up(&hwmon->lock);
84
85 return ret;
86}
87
88#ifdef CONFIG_SENSORS_S3C_RAW
89/**
90 * s3c_hwmon_show_raw - show a conversion from the raw channel number.
91 * @dev: The device that the attribute belongs to.
92 * @attr: The attribute being read.
93 * @buf: The result buffer.
94 *
95 * This show deals with the raw attribute, registered for each possible
96 * ADC channel. This does a conversion and returns the raw (un-scaled)
97 * value returned from the hardware.
98 */
99static ssize_t s3c_hwmon_show_raw(struct device *dev,
100 struct device_attribute *attr, char *buf)
101{
102 struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev));
103 struct sensor_device_attribute *sa = to_sensor_dev_attr(attr);
104 int ret;
105
106 ret = s3c_hwmon_read_ch(dev, adc, sa->index);
107
108 return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
109}
110
111#define DEF_ADC_ATTR(x) \
112 static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
113
114DEF_ADC_ATTR(0);
115DEF_ADC_ATTR(1);
116DEF_ADC_ATTR(2);
117DEF_ADC_ATTR(3);
118DEF_ADC_ATTR(4);
119DEF_ADC_ATTR(5);
120DEF_ADC_ATTR(6);
121DEF_ADC_ATTR(7);
122
123static struct attribute *s3c_hwmon_attrs[9] = {
124 &sensor_dev_attr_adc0_raw.dev_attr.attr,
125 &sensor_dev_attr_adc1_raw.dev_attr.attr,
126 &sensor_dev_attr_adc2_raw.dev_attr.attr,
127 &sensor_dev_attr_adc3_raw.dev_attr.attr,
128 &sensor_dev_attr_adc4_raw.dev_attr.attr,
129 &sensor_dev_attr_adc5_raw.dev_attr.attr,
130 &sensor_dev_attr_adc6_raw.dev_attr.attr,
131 &sensor_dev_attr_adc7_raw.dev_attr.attr,
132 NULL,
133};
134
135static struct attribute_group s3c_hwmon_attrgroup = {
136 .attrs = s3c_hwmon_attrs,
137};
138
139static inline int s3c_hwmon_add_raw(struct device *dev)
140{
141 return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup);
142}
143
144static inline void s3c_hwmon_remove_raw(struct device *dev)
145{
146 sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup);
147}
148
149#else
150
151static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; }
152static inline void s3c_hwmon_remove_raw(struct device *dev) { }
153
154#endif /* CONFIG_SENSORS_S3C_RAW */
155
156/**
157 * s3c_hwmon_ch_show - show value of a given channel
158 * @dev: The device that the attribute belongs to.
159 * @attr: The attribute being read.
160 * @buf: The result buffer.
161 *
162 * Read a value from the ADC and scale it before returning it to the
163 * caller. The scale factor is gained from the channel configuration
164 * passed via the platform data when the device was registered.
165 */
166static ssize_t s3c_hwmon_ch_show(struct device *dev,
167 struct device_attribute *attr,
168 char *buf)
169{
170 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
171 struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
172 struct s3c_hwmon_pdata *pdata = dev->platform_data;
173 struct s3c_hwmon_chcfg *cfg;
174 int ret;
175
176 cfg = pdata->in[sen_attr->index];
177
178 ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index);
179 if (ret < 0)
180 return ret;
181
182 ret *= cfg->mult;
183 ret = DIV_ROUND_CLOSEST(ret, cfg->div);
184
185 return snprintf(buf, PAGE_SIZE, "%d\n", ret);
186}
187
188/**
189 * s3c_hwmon_label_show - show label name of the given channel.
190 * @dev: The device that the attribute belongs to.
191 * @attr: The attribute being read.
192 * @buf: The result buffer.
193 *
194 * Return the label name of a given channel
195 */
196static ssize_t s3c_hwmon_label_show(struct device *dev,
197 struct device_attribute *attr,
198 char *buf)
199{
200 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
201 struct s3c_hwmon_pdata *pdata = dev->platform_data;
202 struct s3c_hwmon_chcfg *cfg;
203
204 cfg = pdata->in[sen_attr->index];
205
206 return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name);
207}
208
209/**
210 * s3c_hwmon_create_attr - create hwmon attribute for given channel.
211 * @dev: The device to create the attribute on.
212 * @cfg: The channel configuration passed from the platform data.
213 * @channel: The ADC channel number to process.
214 *
215 * Create the scaled attribute for use with hwmon from the specified
216 * platform data in @pdata. The sysfs entry is handled by the routine
217 * s3c_hwmon_ch_show().
218 *
219 * The attribute name is taken from the configuration data if present
220 * otherwise the name is taken by concatenating in_ with the channel
221 * number.
222 */
223static int s3c_hwmon_create_attr(struct device *dev,
224 struct s3c_hwmon_chcfg *cfg,
225 struct s3c_hwmon_attr *attrs,
226 int channel)
227{
228 struct sensor_device_attribute *attr;
229 int ret;
230
231 snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel);
232
233 attr = &attrs->in;
234 attr->index = channel;
235 attr->dev_attr.attr.name = attrs->in_name;
236 attr->dev_attr.attr.mode = S_IRUGO;
237 attr->dev_attr.attr.owner = THIS_MODULE;
238 attr->dev_attr.show = s3c_hwmon_ch_show;
239
240 ret = device_create_file(dev, &attr->dev_attr);
241 if (ret < 0) {
242 dev_err(dev, "failed to create input attribute\n");
243 return ret;
244 }
245
246 /* if this has a name, add a label */
247 if (cfg->name) {
248 snprintf(attrs->label_name, sizeof(attrs->label_name),
249 "in%d_label", channel);
250
251 attr = &attrs->label;
252 attr->index = channel;
253 attr->dev_attr.attr.name = attrs->label_name;
254 attr->dev_attr.attr.mode = S_IRUGO;
255 attr->dev_attr.attr.owner = THIS_MODULE;
256 attr->dev_attr.show = s3c_hwmon_label_show;
257
258 ret = device_create_file(dev, &attr->dev_attr);
259 if (ret < 0) {
260 device_remove_file(dev, &attrs->in.dev_attr);
261 dev_err(dev, "failed to create label attribute\n");
262 }
263 }
264
265 return ret;
266}
267
268static void s3c_hwmon_remove_attr(struct device *dev,
269 struct s3c_hwmon_attr *attrs)
270{
271 device_remove_file(dev, &attrs->in.dev_attr);
272 device_remove_file(dev, &attrs->label.dev_attr);
273}
274
275/**
276 * s3c_hwmon_probe - device probe entry.
277 * @dev: The device being probed.
278*/
279static int __devinit s3c_hwmon_probe(struct platform_device *dev)
280{
281 struct s3c_hwmon_pdata *pdata = dev->dev.platform_data;
282 struct s3c_hwmon *hwmon;
283 int ret = 0;
284 int i;
285
286 if (!pdata) {
287 dev_err(&dev->dev, "no platform data supplied\n");
288 return -EINVAL;
289 }
290
291 hwmon = kzalloc(sizeof(struct s3c_hwmon), GFP_KERNEL);
292 if (hwmon == NULL) {
293 dev_err(&dev->dev, "no memory\n");
294 return -ENOMEM;
295 }
296
297 platform_set_drvdata(dev, hwmon);
298
299 init_MUTEX(&hwmon->lock);
300
301 /* Register with the core ADC driver. */
302
303 hwmon->client = s3c_adc_register(dev, NULL, NULL, 0);
304 if (IS_ERR(hwmon->client)) {
305 dev_err(&dev->dev, "cannot register adc\n");
306 ret = PTR_ERR(hwmon->client);
307 goto err_mem;
308 }
309
310 /* add attributes for our adc devices. */
311
312 ret = s3c_hwmon_add_raw(&dev->dev);
313 if (ret)
314 goto err_registered;
315
316 /* register with the hwmon core */
317
318 hwmon->hwmon_dev = hwmon_device_register(&dev->dev);
319 if (IS_ERR(hwmon->hwmon_dev)) {
320 dev_err(&dev->dev, "error registering with hwmon\n");
321 ret = PTR_ERR(hwmon->hwmon_dev);
322 goto err_raw_attribute;
323 }
324
325 for (i = 0; i < ARRAY_SIZE(pdata->in); i++) {
326 if (!pdata->in[i])
327 continue;
328
329 if (pdata->in[i]->mult >= 0x10000)
330 dev_warn(&dev->dev,
331 "channel %d multiplier too large\n",
332 i);
333
334 ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i],
335 &hwmon->attrs[i], i);
336 if (ret) {
337 dev_err(&dev->dev,
338 "error creating channel %d\n", i);
339
340 for (i--; i >= 0; i--)
341 s3c_hwmon_remove_attr(&dev->dev,
342 &hwmon->attrs[i]);
343
344 goto err_hwmon_register;
345 }
346 }
347
348 return 0;
349
350 err_hwmon_register:
351 hwmon_device_unregister(hwmon->hwmon_dev);
352
353 err_raw_attribute:
354 s3c_hwmon_remove_raw(&dev->dev);
355
356 err_registered:
357 s3c_adc_release(hwmon->client);
358
359 err_mem:
360 kfree(hwmon);
361 return ret;
362}
363
364static int __devexit s3c_hwmon_remove(struct platform_device *dev)
365{
366 struct s3c_hwmon *hwmon = platform_get_drvdata(dev);
367 int i;
368
369 s3c_hwmon_remove_raw(&dev->dev);
370
371 for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++)
372 s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]);
373
374 hwmon_device_unregister(hwmon->hwmon_dev);
375 s3c_adc_release(hwmon->client);
376
377 return 0;
378}
379
380static struct platform_driver s3c_hwmon_driver = {
381 .driver = {
382 .name = "s3c-hwmon",
383 .owner = THIS_MODULE,
384 },
385 .probe = s3c_hwmon_probe,
386 .remove = __devexit_p(s3c_hwmon_remove),
387};
388
389static int __init s3c_hwmon_init(void)
390{
391 return platform_driver_register(&s3c_hwmon_driver);
392}
393
394static void __exit s3c_hwmon_exit(void)
395{
396 platform_driver_unregister(&s3c_hwmon_driver);
397}
398
399module_init(s3c_hwmon_init);
400module_exit(s3c_hwmon_exit);
401
402MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
403MODULE_DESCRIPTION("S3C ADC HWMon driver");
404MODULE_LICENSE("GPL v2");
405MODULE_ALIAS("platform:s3c-hwmon");
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index aa2e8318f167..12f2e7086560 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -63,7 +63,7 @@
63#include <linux/mutex.h> 63#include <linux/mutex.h>
64#include <linux/sysfs.h> 64#include <linux/sysfs.h>
65#include <linux/acpi.h> 65#include <linux/acpi.h>
66#include <asm/io.h> 66#include <linux/io.h>
67 67
68 68
69/* If force_addr is set to anything different from 0, we forcibly enable 69/* If force_addr is set to anything different from 0, we forcibly enable
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 6f6d52b4fb64..f46d936c12da 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -37,7 +37,7 @@
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/mutex.h> 38#include <linux/mutex.h>
39#include <linux/acpi.h> 39#include <linux/acpi.h>
40#include <asm/io.h> 40#include <linux/io.h>
41 41
42static unsigned short force_id; 42static unsigned short force_id;
43module_param(force_id, ushort, 0); 43module_param(force_id, ushort, 0);
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index ba75bfcf14ce..8ad50fdba00d 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -38,7 +38,7 @@
38#include <linux/mutex.h> 38#include <linux/mutex.h>
39#include <linux/sysfs.h> 39#include <linux/sysfs.h>
40#include <linux/acpi.h> 40#include <linux/acpi.h>
41#include <asm/io.h> 41#include <linux/io.h>
42 42
43static unsigned short force_id; 43static unsigned short force_id;
44module_param(force_id, ushort, 0); 44module_param(force_id, ushort, 0);
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
new file mode 100644
index 000000000000..20924343431b
--- /dev/null
+++ b/drivers/hwmon/tmp421.c
@@ -0,0 +1,347 @@
1/* tmp421.c
2 *
3 * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
4 * Preliminary support by:
5 * Melvin Rook, Raymond Ng
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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. See the
15 * 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 program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22/*
23 * Driver for the Texas Instruments TMP421 SMBus temperature sensor IC.
24 * Supported models: TMP421, TMP422, TMP423
25 */
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <linux/jiffies.h>
31#include <linux/i2c.h>
32#include <linux/hwmon.h>
33#include <linux/hwmon-sysfs.h>
34#include <linux/err.h>
35#include <linux/mutex.h>
36#include <linux/sysfs.h>
37
38/* Addresses to scan */
39static unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
40 I2C_CLIENT_END };
41
42/* Insmod parameters */
43I2C_CLIENT_INSMOD_3(tmp421, tmp422, tmp423);
44
45/* The TMP421 registers */
46#define TMP421_CONFIG_REG_1 0x09
47#define TMP421_CONVERSION_RATE_REG 0x0B
48#define TMP421_MANUFACTURER_ID_REG 0xFE
49#define TMP421_DEVICE_ID_REG 0xFF
50
51static const u8 TMP421_TEMP_MSB[4] = { 0x00, 0x01, 0x02, 0x03 };
52static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 };
53
54/* Flags */
55#define TMP421_CONFIG_SHUTDOWN 0x40
56#define TMP421_CONFIG_RANGE 0x04
57
58/* Manufacturer / Device ID's */
59#define TMP421_MANUFACTURER_ID 0x55
60#define TMP421_DEVICE_ID 0x21
61#define TMP422_DEVICE_ID 0x22
62#define TMP423_DEVICE_ID 0x23
63
64static const struct i2c_device_id tmp421_id[] = {
65 { "tmp421", tmp421 },
66 { "tmp422", tmp422 },
67 { "tmp423", tmp423 },
68 { }
69};
70MODULE_DEVICE_TABLE(i2c, tmp421_id);
71
72struct tmp421_data {
73 struct device *hwmon_dev;
74 struct mutex update_lock;
75 char valid;
76 unsigned long last_updated;
77 int kind;
78 u8 config;
79 s16 temp[4];
80};
81
82static int temp_from_s16(s16 reg)
83{
84 int temp = reg;
85
86 return (temp * 1000 + 128) / 256;
87}
88
89static int temp_from_u16(u16 reg)
90{
91 int temp = reg;
92
93 /* Add offset for extended temperature range. */
94 temp -= 64 * 256;
95
96 return (temp * 1000 + 128) / 256;
97}
98
99static struct tmp421_data *tmp421_update_device(struct device *dev)
100{
101 struct i2c_client *client = to_i2c_client(dev);
102 struct tmp421_data *data = i2c_get_clientdata(client);
103 int i;
104
105 mutex_lock(&data->update_lock);
106
107 if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
108 data->config = i2c_smbus_read_byte_data(client,
109 TMP421_CONFIG_REG_1);
110
111 for (i = 0; i <= data->kind; i++) {
112 data->temp[i] = i2c_smbus_read_byte_data(client,
113 TMP421_TEMP_MSB[i]) << 8;
114 data->temp[i] |= i2c_smbus_read_byte_data(client,
115 TMP421_TEMP_LSB[i]);
116 }
117 data->last_updated = jiffies;
118 data->valid = 1;
119 }
120
121 mutex_unlock(&data->update_lock);
122
123 return data;
124}
125
126static ssize_t show_temp_value(struct device *dev,
127 struct device_attribute *devattr, char *buf)
128{
129 int index = to_sensor_dev_attr(devattr)->index;
130 struct tmp421_data *data = tmp421_update_device(dev);
131 int temp;
132
133 mutex_lock(&data->update_lock);
134 if (data->config & TMP421_CONFIG_RANGE)
135 temp = temp_from_u16(data->temp[index]);
136 else
137 temp = temp_from_s16(data->temp[index]);
138 mutex_unlock(&data->update_lock);
139
140 return sprintf(buf, "%d\n", temp);
141}
142
143static ssize_t show_fault(struct device *dev,
144 struct device_attribute *devattr, char *buf)
145{
146 int index = to_sensor_dev_attr(devattr)->index;
147 struct tmp421_data *data = tmp421_update_device(dev);
148
149 /*
150 * The OPEN bit signals a fault. This is bit 0 of the temperature
151 * register (low byte).
152 */
153 if (data->temp[index] & 0x01)
154 return sprintf(buf, "1\n");
155 else
156 return sprintf(buf, "0\n");
157}
158
159static mode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a,
160 int n)
161{
162 struct device *dev = container_of(kobj, struct device, kobj);
163 struct tmp421_data *data = dev_get_drvdata(dev);
164 struct device_attribute *devattr;
165 unsigned int index;
166
167 devattr = container_of(a, struct device_attribute, attr);
168 index = to_sensor_dev_attr(devattr)->index;
169
170 if (data->kind > index)
171 return a->mode;
172
173 return 0;
174}
175
176static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0);
177static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1);
178static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
179static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2);
180static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
181static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3);
182static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
183
184static struct attribute *tmp421_attr[] = {
185 &sensor_dev_attr_temp1_input.dev_attr.attr,
186 &sensor_dev_attr_temp2_input.dev_attr.attr,
187 &sensor_dev_attr_temp2_fault.dev_attr.attr,
188 &sensor_dev_attr_temp3_input.dev_attr.attr,
189 &sensor_dev_attr_temp3_fault.dev_attr.attr,
190 &sensor_dev_attr_temp4_input.dev_attr.attr,
191 &sensor_dev_attr_temp4_fault.dev_attr.attr,
192 NULL
193};
194
195static const struct attribute_group tmp421_group = {
196 .attrs = tmp421_attr,
197 .is_visible = tmp421_is_visible,
198};
199
200static int tmp421_init_client(struct i2c_client *client)
201{
202 int config, config_orig;
203
204 /* Set the conversion rate to 2 Hz */
205 i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05);
206
207 /* Start conversions (disable shutdown if necessary) */
208 config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
209 if (config < 0) {
210 dev_err(&client->dev, "Could not read configuration"
211 " register (%d)\n", config);
212 return -ENODEV;
213 }
214
215 config_orig = config;
216 config &= ~TMP421_CONFIG_SHUTDOWN;
217
218 if (config != config_orig) {
219 dev_info(&client->dev, "Enable monitoring chip\n");
220 i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config);
221 }
222
223 return 0;
224}
225
226static int tmp421_detect(struct i2c_client *client, int kind,
227 struct i2c_board_info *info)
228{
229 struct i2c_adapter *adapter = client->adapter;
230 const char *names[] = { "TMP421", "TMP422", "TMP423" };
231
232 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
233 return -ENODEV;
234
235 if (kind <= 0) {
236 u8 reg;
237
238 reg = i2c_smbus_read_byte_data(client,
239 TMP421_MANUFACTURER_ID_REG);
240 if (reg != TMP421_MANUFACTURER_ID)
241 return -ENODEV;
242
243 reg = i2c_smbus_read_byte_data(client,
244 TMP421_DEVICE_ID_REG);
245 switch (reg) {
246 case TMP421_DEVICE_ID:
247 kind = tmp421;
248 break;
249 case TMP422_DEVICE_ID:
250 kind = tmp422;
251 break;
252 case TMP423_DEVICE_ID:
253 kind = tmp423;
254 break;
255 default:
256 return -ENODEV;
257 }
258 }
259 strlcpy(info->type, tmp421_id[kind - 1].name, I2C_NAME_SIZE);
260 dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n",
261 names[kind - 1], client->addr);
262
263 return 0;
264}
265
266static int tmp421_probe(struct i2c_client *client,
267 const struct i2c_device_id *id)
268{
269 struct tmp421_data *data;
270 int err;
271
272 data = kzalloc(sizeof(struct tmp421_data), GFP_KERNEL);
273 if (!data)
274 return -ENOMEM;
275
276 i2c_set_clientdata(client, data);
277 mutex_init(&data->update_lock);
278 data->kind = id->driver_data;
279
280 err = tmp421_init_client(client);
281 if (err)
282 goto exit_free;
283
284 err = sysfs_create_group(&client->dev.kobj, &tmp421_group);
285 if (err)
286 goto exit_free;
287
288 data->hwmon_dev = hwmon_device_register(&client->dev);
289 if (IS_ERR(data->hwmon_dev)) {
290 err = PTR_ERR(data->hwmon_dev);
291 data->hwmon_dev = NULL;
292 goto exit_remove;
293 }
294 return 0;
295
296exit_remove:
297 sysfs_remove_group(&client->dev.kobj, &tmp421_group);
298
299exit_free:
300 i2c_set_clientdata(client, NULL);
301 kfree(data);
302
303 return err;
304}
305
306static int tmp421_remove(struct i2c_client *client)
307{
308 struct tmp421_data *data = i2c_get_clientdata(client);
309
310 hwmon_device_unregister(data->hwmon_dev);
311 sysfs_remove_group(&client->dev.kobj, &tmp421_group);
312
313 i2c_set_clientdata(client, NULL);
314 kfree(data);
315
316 return 0;
317}
318
319static struct i2c_driver tmp421_driver = {
320 .class = I2C_CLASS_HWMON,
321 .driver = {
322 .name = "tmp421",
323 },
324 .probe = tmp421_probe,
325 .remove = tmp421_remove,
326 .id_table = tmp421_id,
327 .detect = tmp421_detect,
328 .address_data = &addr_data,
329};
330
331static int __init tmp421_init(void)
332{
333 return i2c_add_driver(&tmp421_driver);
334}
335
336static void __exit tmp421_exit(void)
337{
338 i2c_del_driver(&tmp421_driver);
339}
340
341MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
342MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
343 " driver");
344MODULE_LICENSE("GPL");
345
346module_init(tmp421_init);
347module_exit(tmp421_exit);
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index a022aedcaacb..39e82a492f26 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -42,7 +42,7 @@
42#include <linux/mutex.h> 42#include <linux/mutex.h>
43#include <linux/sysfs.h> 43#include <linux/sysfs.h>
44#include <linux/acpi.h> 44#include <linux/acpi.h>
45#include <asm/io.h> 45#include <linux/io.h>
46 46
47 47
48/* If force_addr is set to anything different from 0, we forcibly enable 48/* If force_addr is set to anything different from 0, we forcibly enable
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 73f77a9b8b18..ae33bbb577c7 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -33,7 +33,7 @@
33#include <linux/mutex.h> 33#include <linux/mutex.h>
34#include <linux/ioport.h> 34#include <linux/ioport.h>
35#include <linux/acpi.h> 35#include <linux/acpi.h>
36#include <asm/io.h> 36#include <linux/io.h>
37 37
38static int uch_config = -1; 38static int uch_config = -1;
39module_param(uch_config, int, 0); 39module_param(uch_config, int, 0);
@@ -1136,7 +1136,7 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
1136 } 1136 }
1137 1137
1138 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1138 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1139 if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { 1139 if (!request_region(res->start, resource_size(res), DRVNAME)) {
1140 err = -EBUSY; 1140 err = -EBUSY;
1141 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", 1141 dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
1142 (unsigned long)res->start, (unsigned long)res->end); 1142 (unsigned long)res->start, (unsigned long)res->end);
@@ -1209,7 +1209,7 @@ EXIT_DEV_REMOVE:
1209 dev_err(dev, "Sysfs interface creation failed (%d)\n", err); 1209 dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
1210EXIT_DEV_REMOVE_SILENT: 1210EXIT_DEV_REMOVE_SILENT:
1211 vt1211_remove_sysfs(pdev); 1211 vt1211_remove_sysfs(pdev);
1212 release_region(res->start, res->end - res->start + 1); 1212 release_region(res->start, resource_size(res));
1213EXIT_KFREE: 1213EXIT_KFREE:
1214 platform_set_drvdata(pdev, NULL); 1214 platform_set_drvdata(pdev, NULL);
1215 kfree(data); 1215 kfree(data);
@@ -1228,7 +1228,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
1228 kfree(data); 1228 kfree(data);
1229 1229
1230 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1230 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1231 release_region(res->start, res->end - res->start + 1); 1231 release_region(res->start, resource_size(res));
1232 1232
1233 return 0; 1233 return 0;
1234} 1234}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 9982b45fbb14..470a1226ba2b 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -36,7 +36,7 @@
36#include <linux/err.h> 36#include <linux/err.h>
37#include <linux/mutex.h> 37#include <linux/mutex.h>
38#include <linux/acpi.h> 38#include <linux/acpi.h>
39#include <asm/io.h> 39#include <linux/io.h>
40 40
41static int force_addr; 41static int force_addr;
42module_param(force_addr, int, 0); 42module_param(force_addr, int, 0);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 0e9746913d2b..bb5e78748783 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -51,7 +51,7 @@
51#include <linux/err.h> 51#include <linux/err.h>
52#include <linux/mutex.h> 52#include <linux/mutex.h>
53#include <linux/acpi.h> 53#include <linux/acpi.h>
54#include <asm/io.h> 54#include <linux/io.h>
55#include "lm75.h" 55#include "lm75.h"
56 56
57enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; 57enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg };
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 389150ba30d3..2be28ac4ede0 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -51,7 +51,7 @@
51#include <linux/mutex.h> 51#include <linux/mutex.h>
52#include <linux/ioport.h> 52#include <linux/ioport.h>
53#include <linux/acpi.h> 53#include <linux/acpi.h>
54#include <asm/io.h> 54#include <linux/io.h>
55#include "lm75.h" 55#include "lm75.h"
56 56
57static struct platform_device *pdev; 57static struct platform_device *pdev;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 0bdab959b736..d27ed1bac002 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -48,7 +48,7 @@
48#ifdef CONFIG_ISA 48#ifdef CONFIG_ISA
49#include <linux/platform_device.h> 49#include <linux/platform_device.h>
50#include <linux/ioport.h> 50#include <linux/ioport.h>
51#include <asm/io.h> 51#include <linux/io.h>
52#endif 52#endif
53 53
54#include "lm75.h" 54#include "lm75.h"
diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c
new file mode 100644
index 000000000000..c16e9e74c356
--- /dev/null
+++ b/drivers/hwmon/wm831x-hwmon.c
@@ -0,0 +1,226 @@
1/*
2 * drivers/hwmon/wm831x-hwmon.c - Wolfson Microelectronics WM831x PMIC
3 * hardware monitoring features.
4 *
5 * Copyright (C) 2009 Wolfson Microelectronics plc
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License v2 as published by the
9 * Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/platform_device.h>
24#include <linux/err.h>
25#include <linux/hwmon.h>
26#include <linux/hwmon-sysfs.h>
27
28#include <linux/mfd/wm831x/core.h>
29#include <linux/mfd/wm831x/auxadc.h>
30
31struct wm831x_hwmon {
32 struct wm831x *wm831x;
33 struct device *classdev;
34};
35
36static ssize_t show_name(struct device *dev,
37 struct device_attribute *attr, char *buf)
38{
39 return sprintf(buf, "wm831x\n");
40}
41
42static const char *input_names[] = {
43 [WM831X_AUX_SYSVDD] = "SYSVDD",
44 [WM831X_AUX_USB] = "USB",
45 [WM831X_AUX_BKUP_BATT] = "Backup battery",
46 [WM831X_AUX_BATT] = "Battery",
47 [WM831X_AUX_WALL] = "WALL",
48 [WM831X_AUX_CHIP_TEMP] = "PMIC",
49 [WM831X_AUX_BATT_TEMP] = "Battery",
50};
51
52
53static ssize_t show_voltage(struct device *dev,
54 struct device_attribute *attr, char *buf)
55{
56 struct wm831x_hwmon *hwmon = dev_get_drvdata(dev);
57 int channel = to_sensor_dev_attr(attr)->index;
58 int ret;
59
60 ret = wm831x_auxadc_read_uv(hwmon->wm831x, channel);
61 if (ret < 0)
62 return ret;
63
64 return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret, 1000));
65}
66
67static ssize_t show_chip_temp(struct device *dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct wm831x_hwmon *hwmon = dev_get_drvdata(dev);
71 int channel = to_sensor_dev_attr(attr)->index;
72 int ret;
73
74 ret = wm831x_auxadc_read(hwmon->wm831x, channel);
75 if (ret < 0)
76 return ret;
77
78 /* Degrees celsius = (512.18-ret) / 1.0983 */
79 ret = 512180 - (ret * 1000);
80 ret = DIV_ROUND_CLOSEST(ret * 10000, 10983);
81
82 return sprintf(buf, "%d\n", ret);
83}
84
85static ssize_t show_label(struct device *dev,
86 struct device_attribute *attr, char *buf)
87{
88 int channel = to_sensor_dev_attr(attr)->index;
89
90 return sprintf(buf, "%s\n", input_names[channel]);
91}
92
93#define WM831X_VOLTAGE(id, name) \
94 static SENSOR_DEVICE_ATTR(in##id##_input, S_IRUGO, show_voltage, \
95 NULL, name)
96
97#define WM831X_NAMED_VOLTAGE(id, name) \
98 WM831X_VOLTAGE(id, name); \
99 static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
100 NULL, name)
101
102static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
103
104WM831X_VOLTAGE(0, WM831X_AUX_AUX1);
105WM831X_VOLTAGE(1, WM831X_AUX_AUX2);
106WM831X_VOLTAGE(2, WM831X_AUX_AUX3);
107WM831X_VOLTAGE(3, WM831X_AUX_AUX4);
108
109WM831X_NAMED_VOLTAGE(4, WM831X_AUX_SYSVDD);
110WM831X_NAMED_VOLTAGE(5, WM831X_AUX_USB);
111WM831X_NAMED_VOLTAGE(6, WM831X_AUX_BATT);
112WM831X_NAMED_VOLTAGE(7, WM831X_AUX_WALL);
113WM831X_NAMED_VOLTAGE(8, WM831X_AUX_BKUP_BATT);
114
115static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_chip_temp, NULL,
116 WM831X_AUX_CHIP_TEMP);
117static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
118 WM831X_AUX_CHIP_TEMP);
119/* Report as a voltage since conversion depends on external components
120 * and that's what the ABI wants. */
121static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_voltage, NULL,
122 WM831X_AUX_BATT_TEMP);
123static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
124 WM831X_AUX_BATT_TEMP);
125
126static struct attribute *wm831x_attributes[] = {
127 &dev_attr_name.attr,
128
129 &sensor_dev_attr_in0_input.dev_attr.attr,
130 &sensor_dev_attr_in1_input.dev_attr.attr,
131 &sensor_dev_attr_in2_input.dev_attr.attr,
132 &sensor_dev_attr_in3_input.dev_attr.attr,
133
134 &sensor_dev_attr_in4_input.dev_attr.attr,
135 &sensor_dev_attr_in4_label.dev_attr.attr,
136 &sensor_dev_attr_in5_input.dev_attr.attr,
137 &sensor_dev_attr_in5_label.dev_attr.attr,
138 &sensor_dev_attr_in6_input.dev_attr.attr,
139 &sensor_dev_attr_in6_label.dev_attr.attr,
140 &sensor_dev_attr_in7_input.dev_attr.attr,
141 &sensor_dev_attr_in7_label.dev_attr.attr,
142 &sensor_dev_attr_in8_input.dev_attr.attr,
143 &sensor_dev_attr_in8_label.dev_attr.attr,
144
145 &sensor_dev_attr_temp1_input.dev_attr.attr,
146 &sensor_dev_attr_temp1_label.dev_attr.attr,
147 &sensor_dev_attr_temp2_input.dev_attr.attr,
148 &sensor_dev_attr_temp2_label.dev_attr.attr,
149
150 NULL
151};
152
153static const struct attribute_group wm831x_attr_group = {
154 .attrs = wm831x_attributes,
155};
156
157static int __devinit wm831x_hwmon_probe(struct platform_device *pdev)
158{
159 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
160 struct wm831x_hwmon *hwmon;
161 int ret;
162
163 hwmon = kzalloc(sizeof(struct wm831x_hwmon), GFP_KERNEL);
164 if (!hwmon)
165 return -ENOMEM;
166
167 hwmon->wm831x = wm831x;
168
169 ret = sysfs_create_group(&pdev->dev.kobj, &wm831x_attr_group);
170 if (ret)
171 goto err;
172
173 hwmon->classdev = hwmon_device_register(&pdev->dev);
174 if (IS_ERR(hwmon->classdev)) {
175 ret = PTR_ERR(hwmon->classdev);
176 goto err_sysfs;
177 }
178
179 platform_set_drvdata(pdev, hwmon);
180
181 return 0;
182
183err_sysfs:
184 sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
185err:
186 kfree(hwmon);
187 return ret;
188}
189
190static int __devexit wm831x_hwmon_remove(struct platform_device *pdev)
191{
192 struct wm831x_hwmon *hwmon = platform_get_drvdata(pdev);
193
194 hwmon_device_unregister(hwmon->classdev);
195 sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
196 platform_set_drvdata(pdev, NULL);
197 kfree(hwmon);
198
199 return 0;
200}
201
202static struct platform_driver wm831x_hwmon_driver = {
203 .probe = wm831x_hwmon_probe,
204 .remove = __devexit_p(wm831x_hwmon_remove),
205 .driver = {
206 .name = "wm831x-hwmon",
207 .owner = THIS_MODULE,
208 },
209};
210
211static int __init wm831x_hwmon_init(void)
212{
213 return platform_driver_register(&wm831x_hwmon_driver);
214}
215module_init(wm831x_hwmon_init);
216
217static void __exit wm831x_hwmon_exit(void)
218{
219 platform_driver_unregister(&wm831x_hwmon_driver);
220}
221module_exit(wm831x_hwmon_exit);
222
223MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
224MODULE_DESCRIPTION("WM831x Hardware Monitoring");
225MODULE_LICENSE("GPL");
226MODULE_ALIAS("platform:wm831x-hwmon");
diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c
new file mode 100644
index 000000000000..13290595ca86
--- /dev/null
+++ b/drivers/hwmon/wm8350-hwmon.c
@@ -0,0 +1,151 @@
1/*
2 * drivers/hwmon/wm8350-hwmon.c - Wolfson Microelectronics WM8350 PMIC
3 * hardware monitoring features.
4 *
5 * Copyright (C) 2009 Wolfson Microelectronics plc
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License v2 as published by the
9 * Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/err.h>
24#include <linux/platform_device.h>
25#include <linux/hwmon.h>
26#include <linux/hwmon-sysfs.h>
27
28#include <linux/mfd/wm8350/core.h>
29#include <linux/mfd/wm8350/comparator.h>
30
31static ssize_t show_name(struct device *dev,
32 struct device_attribute *attr, char *buf)
33{
34 return sprintf(buf, "wm8350\n");
35}
36
37static const char *input_names[] = {
38 [WM8350_AUXADC_USB] = "USB",
39 [WM8350_AUXADC_LINE] = "Line",
40 [WM8350_AUXADC_BATT] = "Battery",
41};
42
43
44static ssize_t show_voltage(struct device *dev,
45 struct device_attribute *attr, char *buf)
46{
47 struct wm8350 *wm8350 = dev_get_drvdata(dev);
48 int channel = to_sensor_dev_attr(attr)->index;
49 int val;
50
51 val = wm8350_read_auxadc(wm8350, channel, 0, 0) * WM8350_AUX_COEFF;
52 val = DIV_ROUND_CLOSEST(val, 1000);
53
54 return sprintf(buf, "%d\n", val);
55}
56
57static ssize_t show_label(struct device *dev,
58 struct device_attribute *attr, char *buf)
59{
60 int channel = to_sensor_dev_attr(attr)->index;
61
62 return sprintf(buf, "%s\n", input_names[channel]);
63}
64
65#define WM8350_NAMED_VOLTAGE(id, name) \
66 static SENSOR_DEVICE_ATTR(in##id##_input, S_IRUGO, show_voltage,\
67 NULL, name); \
68 static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
69 NULL, name)
70
71static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
72
73WM8350_NAMED_VOLTAGE(0, WM8350_AUXADC_USB);
74WM8350_NAMED_VOLTAGE(1, WM8350_AUXADC_BATT);
75WM8350_NAMED_VOLTAGE(2, WM8350_AUXADC_LINE);
76
77static struct attribute *wm8350_attributes[] = {
78 &dev_attr_name.attr,
79
80 &sensor_dev_attr_in0_input.dev_attr.attr,
81 &sensor_dev_attr_in0_label.dev_attr.attr,
82 &sensor_dev_attr_in1_input.dev_attr.attr,
83 &sensor_dev_attr_in1_label.dev_attr.attr,
84 &sensor_dev_attr_in2_input.dev_attr.attr,
85 &sensor_dev_attr_in2_label.dev_attr.attr,
86
87 NULL,
88};
89
90static const struct attribute_group wm8350_attr_group = {
91 .attrs = wm8350_attributes,
92};
93
94static int __devinit wm8350_hwmon_probe(struct platform_device *pdev)
95{
96 struct wm8350 *wm8350 = platform_get_drvdata(pdev);
97 int ret;
98
99 ret = sysfs_create_group(&pdev->dev.kobj, &wm8350_attr_group);
100 if (ret)
101 goto err;
102
103 wm8350->hwmon.classdev = hwmon_device_register(&pdev->dev);
104 if (IS_ERR(wm8350->hwmon.classdev)) {
105 ret = PTR_ERR(wm8350->hwmon.classdev);
106 goto err_group;
107 }
108
109 return 0;
110
111err_group:
112 sysfs_remove_group(&pdev->dev.kobj, &wm8350_attr_group);
113err:
114 return ret;
115}
116
117static int __devexit wm8350_hwmon_remove(struct platform_device *pdev)
118{
119 struct wm8350 *wm8350 = platform_get_drvdata(pdev);
120
121 hwmon_device_unregister(wm8350->hwmon.classdev);
122 sysfs_remove_group(&pdev->dev.kobj, &wm8350_attr_group);
123
124 return 0;
125}
126
127static struct platform_driver wm8350_hwmon_driver = {
128 .probe = wm8350_hwmon_probe,
129 .remove = __devexit_p(wm8350_hwmon_remove),
130 .driver = {
131 .name = "wm8350-hwmon",
132 .owner = THIS_MODULE,
133 },
134};
135
136static int __init wm8350_hwmon_init(void)
137{
138 return platform_driver_register(&wm8350_hwmon_driver);
139}
140module_init(wm8350_hwmon_init);
141
142static void __exit wm8350_hwmon_exit(void)
143{
144 platform_driver_unregister(&wm8350_hwmon_driver);
145}
146module_exit(wm8350_hwmon_exit);
147
148MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
149MODULE_DESCRIPTION("WM8350 Hardware Monitoring");
150MODULE_LICENSE("GPL");
151MODULE_ALIAS("platform:wm8350-hwmon");