summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig88
-rw-r--r--drivers/hwmon/Makefile5
-rw-r--r--drivers/hwmon/adm1021.c35
-rw-r--r--drivers/hwmon/adm1025.c31
-rw-r--r--drivers/hwmon/adm1026.c25
-rw-r--r--drivers/hwmon/adm1031.c24
-rw-r--r--drivers/hwmon/adm9240.c33
-rw-r--r--drivers/hwmon/asb100.c56
-rw-r--r--drivers/hwmon/atxp1.c26
-rw-r--r--drivers/hwmon/ds1621.c29
-rw-r--r--drivers/hwmon/fscher.c27
-rw-r--r--drivers/hwmon/fscpos.c27
-rw-r--r--drivers/hwmon/gl518sm.c28
-rw-r--r--drivers/hwmon/gl520sm.c31
-rw-r--r--drivers/hwmon/hdaps.c616
-rw-r--r--drivers/hwmon/hwmon-vid.c189
-rw-r--r--drivers/hwmon/hwmon.c98
-rw-r--r--drivers/hwmon/it87.c76
-rw-r--r--drivers/hwmon/lm63.c27
-rw-r--r--drivers/hwmon/lm75.c41
-rw-r--r--drivers/hwmon/lm75.h2
-rw-r--r--drivers/hwmon/lm77.c24
-rw-r--r--drivers/hwmon/lm78.c84
-rw-r--r--drivers/hwmon/lm80.c27
-rw-r--r--drivers/hwmon/lm83.c27
-rw-r--r--drivers/hwmon/lm85.c39
-rw-r--r--drivers/hwmon/lm87.c31
-rw-r--r--drivers/hwmon/lm90.c27
-rw-r--r--drivers/hwmon/lm92.c28
-rw-r--r--drivers/hwmon/max1619.c28
-rw-r--r--drivers/hwmon/pc87360.c852
-rw-r--r--drivers/hwmon/sis5595.c73
-rw-r--r--drivers/hwmon/smsc47b397.c74
-rw-r--r--drivers/hwmon/smsc47m1.c74
-rw-r--r--drivers/hwmon/via686a.c79
-rw-r--r--drivers/hwmon/w83627ehf.c64
-rw-r--r--drivers/hwmon/w83627hf.c94
-rw-r--r--drivers/hwmon/w83781d.c90
-rw-r--r--drivers/hwmon/w83792d.c1649
-rw-r--r--drivers/hwmon/w83l785ts.c27
40 files changed, 3868 insertions, 1037 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 140d5f851a5b..db358cfa7cbf 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -12,12 +12,20 @@ config HWMON
of a system. Most modern motherboards include such a device. It
can include temperature sensors, voltage sensors, fan speed
sensors and various additional features such as the ability to
- control the speed of the fans.
+ control the speed of the fans. If you want this support you
+ should say Y here and also to the specific driver(s) for your
+ sensors chip(s) below.
+
+ This support can also be built as a module. If so, the module
+ will be called hwmon.
+
+config HWMON_VID
+ tristate
+ default n
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1021
and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -30,7 +38,7 @@ config SENSORS_ADM1021
config SENSORS_ADM1025
tristate "Analog Devices ADM1025 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1025
and Philips NE1619 sensor chips.
@@ -41,7 +49,7 @@ config SENSORS_ADM1025
config SENSORS_ADM1026
tristate "Analog Devices ADM1026 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1026
sensor chip.
@@ -52,7 +60,6 @@ config SENSORS_ADM1026
config SENSORS_ADM1031
tristate "Analog Devices ADM1031 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Analog Devices ADM1031
and ADM1030 sensor chips.
@@ -63,7 +70,7 @@ config SENSORS_ADM1031
config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM9240,
Dallas DS1780, National Semiconductor LM81 sensor chips.
@@ -74,7 +81,7 @@ config SENSORS_ADM9240
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
chip found on some Asus mainboards.
@@ -85,7 +92,7 @@ config SENSORS_ASB100
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for the Attansic ATXP1 VID
controller.
@@ -99,7 +106,6 @@ config SENSORS_ATXP1
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Dallas Semiconductor
DS1621 and DS1625 sensor chips.
@@ -110,7 +116,6 @@ config SENSORS_DS1621
config SENSORS_FSCHER
tristate "FSC Hermes"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -121,7 +126,6 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -132,7 +136,6 @@ config SENSORS_FSCPOS
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for Genesys Logic GL518SM
sensor chips.
@@ -143,7 +146,7 @@ config SENSORS_GL518SM
config SENSORS_GL520SM
tristate "Genesys Logic GL520SM"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for Genesys Logic GL520SM
sensor chips.
@@ -154,7 +157,8 @@ config SENSORS_GL520SM
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for ITE IT87xx sensor chips
and clones: SiS960.
@@ -165,7 +169,6 @@ config SENSORS_IT87
config SENSORS_LM63
tristate "National Semiconductor LM63"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for the National Semiconductor
LM63 remote diode digital temperature sensor with integrated fan
@@ -178,7 +181,6 @@ config SENSORS_LM63
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM75
sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
@@ -194,7 +196,6 @@ config SENSORS_LM75
config SENSORS_LM77
tristate "National Semiconductor LM77"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM77
sensor chips.
@@ -205,7 +206,8 @@ config SENSORS_LM77
config SENSORS_LM78
tristate "National Semiconductor LM78 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM78,
LM78-J and LM79.
@@ -216,7 +218,6 @@ config SENSORS_LM78
config SENSORS_LM80
tristate "National Semiconductor LM80"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM80 sensor chips.
@@ -227,7 +228,6 @@ config SENSORS_LM80
config SENSORS_LM83
tristate "National Semiconductor LM83"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM83 sensor chips.
@@ -238,7 +238,7 @@ config SENSORS_LM83
config SENSORS_LM85
tristate "National Semiconductor LM85 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM85
sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
@@ -249,7 +249,7 @@ config SENSORS_LM85
config SENSORS_LM87
tristate "National Semiconductor LM87"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
+ select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
sensor chips.
@@ -260,7 +260,6 @@ config SENSORS_LM87
config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
depends on HWMON && I2C
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
@@ -275,7 +274,6 @@ config SENSORS_LM90
config SENSORS_LM92
tristate "National Semiconductor LM92 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM92
and Maxim MAX6635 sensor chips.
@@ -286,7 +284,6 @@ config SENSORS_LM92
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for MAX1619 sensor chip.
@@ -296,8 +293,8 @@ config SENSORS_MAX1619
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get access to the hardware monitoring
functions of the National Semiconductor PC8736x Super-I/O chips.
@@ -311,7 +308,6 @@ config SENSORS_PC87360
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
depends on HWMON && I2C && PCI && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -323,7 +319,6 @@ config SENSORS_SIS5595
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated fan
@@ -336,7 +331,6 @@ config SENSORS_SMSC47M1
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the SMSC LPC47B397-NC
@@ -348,7 +342,6 @@ config SENSORS_SMSC47B397
config SENSORS_VIA686A
tristate "VIA686A"
depends on HWMON && I2C && PCI
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -360,7 +353,8 @@ config SENSORS_VIA686A
config SENSORS_W83781D
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
depends on HWMON && I2C
- select I2C_SENSOR
+ select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for the Winbond W8378x series
of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
@@ -369,10 +363,18 @@ config SENSORS_W83781D
This driver can also be built as a module. If so, the module
will be called w83781d.
+config SENSORS_W83792D
+ tristate "Winbond W83792D"
+ depends on HWMON && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Winbond W83792D chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83792d.
+
config SENSORS_W83L785TS
tristate "Winbond W83L785TS-S"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
help
If you say yes here you get support for the Winbond W83L785TS-S
sensor chip, which is used on the Asus A7N8X, among other
@@ -384,8 +386,8 @@ config SENSORS_W83L785TS
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
+ select HWMON_VID
help
If you say yes here you get support for the Winbond W836X7 series
of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
@@ -396,7 +398,6 @@ config SENSORS_W83627HF
config SENSORS_W83627EHF
tristate "Winbond W83627EHF"
depends on HWMON && I2C && EXPERIMENTAL
- select I2C_SENSOR
select I2C_ISA
help
If you say yes here you get preliminary support for the hardware
@@ -404,9 +405,28 @@ config SENSORS_W83627EHF
Only fan and temperature inputs are supported at the moment, while
the chip does much more than that.
+ This driver also supports the W83627EHG, which is the lead-free
+ version of the W83627EHF.
+
This driver can also be built as a module. If so, the module
will be called w83627ehf.
+config SENSORS_HDAPS
+ tristate "IBM Hard Drive Active Protection System (hdaps)"
+ depends on HWMON && INPUT && X86
+ default n
+ help
+ This driver provides support for the IBM Hard Drive Active Protection
+ System (hdaps), which provides an accelerometer and other misc. data.
+ ThinkPads starting with the R50, T41, and X40 are supported. The
+ accelerometer data is readable via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of hdaps.
+
config HWMON_DEBUG_CHIP
bool "Hardware Monitoring Chip debugging messages"
depends on HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2781403a0236..f7d6a2f61ee7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -2,9 +2,13 @@
# Makefile for sensor chip drivers.
#
+obj-$(CONFIG_HWMON) += hwmon.o
+obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
+
# asb100, then w83781d go first, as they can override other drivers' addresses.
obj-$(CONFIG_SENSORS_ASB100) += asb100.o
obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
+obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
@@ -18,6 +22,7 @@ obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index d2c774c32f45..e928cdb041cb 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -24,7 +24,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
@@ -32,10 +33,9 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
/* adm1021 constants specified below */
@@ -89,6 +89,7 @@ clearing it. Weird, ey? --Phil */
/* Each client has this additional data */
struct adm1021_data {
struct i2c_client client;
+ struct class_device *class_dev;
enum chips type;
struct semaphore update_lock;
@@ -185,7 +186,7 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1021_detect);
+ return i2c_probe(adapter, &addr_data, adm1021_detect);
}
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -196,15 +197,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
int err = 0;
const char *type_name = "";
- /* Make sure we aren't probing the ISA bus!! This is just a safety check
- at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
- if (i2c_is_isa_adapter(adapter)) {
- dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n");
- return 0;
- }
-#endif
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto error0;
@@ -295,6 +287,12 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
adm1021_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error2;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
@@ -305,6 +303,8 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+error2:
+ i2c_detach_client(new_client);
error1:
kfree(data);
error0:
@@ -322,14 +322,15 @@ static void adm1021_init_client(struct i2c_client *client)
static int adm1021_detach_client(struct i2c_client *client)
{
+ struct adm1021_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index e452d0daf906..526b7ff179eb 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -50,8 +50,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -60,13 +61,12 @@
*/
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_2(adm1025, ne1619);
+I2C_CLIENT_INSMOD_2(adm1025, ne1619);
/*
* The ADM1025 registers
@@ -132,6 +132,7 @@ static struct i2c_driver adm1025_driver = {
struct adm1025_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -312,7 +313,7 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1025_detect);
+ return i2c_probe(adapter, &addr_data, adm1025_detect);
}
/*
@@ -416,6 +417,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
adm1025_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -452,6 +459,8 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -464,7 +473,7 @@ static void adm1025_init_client(struct i2c_client *client)
struct adm1025_data *data = i2c_get_clientdata(client);
int i;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/*
* Set high limits
@@ -502,15 +511,15 @@ static void adm1025_init_client(struct i2c_client *client)
static int adm1025_detach_client(struct i2c_client *client)
{
+ struct adm1025_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index c8a7f47911f9..625158110fd4 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -28,16 +28,16 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(adm1026);
+I2C_CLIENT_INSMOD_1(adm1026);
static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
@@ -259,6 +259,7 @@ struct pwm_data {
struct adm1026_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -319,13 +320,15 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter)
if (!(adapter->class & I2C_CLASS_HWMON)) {
return 0;
}
- return i2c_detect(adapter, &addr_data, adm1026_detect);
+ return i2c_probe(adapter, &addr_data, adm1026_detect);
}
int adm1026_detach_client(struct i2c_client *client)
{
+ struct adm1026_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1549,12 +1552,18 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
goto exitfree;
/* Set the VRM version */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/* Initialize the ADM1026 chip */
adm1026_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exitdetach;
+ }
+
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
@@ -1690,6 +1699,8 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
return 0;
/* Error out and cleanup code */
+exitdetach:
+ i2c_detach_client(new_client);
exitfree:
kfree(data);
exit:
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 936250957270..58338ed7c8a1 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -26,7 +26,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Following macros takes channel parameter starting from 0 to 2 */
#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr))
@@ -59,16 +60,16 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(adm1030, adm1031);
+I2C_CLIENT_INSMOD_2(adm1030, adm1031);
typedef u8 auto_chan_table_t[8][2];
/* Each client has this additional data */
struct adm1031_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
int chip_type;
char valid; /* !=0 if following fields are valid */
@@ -725,10 +726,10 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm1031_detect);
+ return i2c_probe(adapter, &addr_data, adm1031_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -788,6 +789,12 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
adm1031_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_div);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -833,6 +840,8 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -841,11 +850,14 @@ exit:
static int adm1031_detach_client(struct i2c_client *client)
{
+ struct adm1031_data *data = i2c_get_clientdata(client);
int ret;
+
+ hwmon_device_unregister(data->class_dev);
if ((ret = i2c_detach_client(client)) != 0) {
return ret;
}
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index ce2a6eb93f6e..bc7faef162f7 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -45,17 +45,16 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
/* Insmod parameters */
-SENSORS_INSMOD_3(adm9240, ds1780, lm81);
+I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81);
/* ADM9240 registers */
#define ADM9240_REG_MAN_ID 0x3e
@@ -150,6 +149,7 @@ static struct i2c_driver adm9240_driver = {
struct adm9240_data {
enum chips type;
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid;
unsigned long last_updated_measure;
@@ -582,6 +582,12 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
adm9240_init_client(new_client);
/* populate sysfs filesystem */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -615,6 +621,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
return 0;
+
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -625,20 +634,20 @@ static int adm9240_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, adm9240_detect);
+ return i2c_probe(adapter, &addr_data, adm9240_detect);
}
static int adm9240_detach_client(struct i2c_client *client)
{
+ struct adm9240_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -648,7 +657,7 @@ static void adm9240_init_client(struct i2c_client *client)
u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
- data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
+ data->vrm = vid_which_vrm(); /* need this to report vid as mV */
dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
data->vrm % 10);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 70d996d6fe0a..8e34855a6274 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -39,8 +39,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include "lm75.h"
@@ -54,11 +55,8 @@
/* I2C addresses to scan */
static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
-/* ISA addresses to scan (none) */
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-
/* Insmod parameters */
-SENSORS_INSMOD_1(asb100);
+I2C_CLIENT_INSMOD_1(asb100);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
@@ -183,6 +181,7 @@ static u8 DIV_TO_REG(long val)
dynamically allocated, at the same time the client itself is allocated. */
struct asb100_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -621,7 +620,7 @@ static int asb100_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, asb100_detect);
+ return i2c_probe(adapter, &addr_data, asb100_detect);
}
static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
@@ -714,14 +713,6 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *new_client;
struct asb100_data *data;
- /* asb100 is SMBus only */
- if (i2c_is_isa_adapter(adapter)) {
- pr_debug("asb100.o: detect failed, "
- "cannot attach to legacy adapter!\n");
- err = -ENODEV;
- goto ERROR0;
- }
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("asb100.o: detect failed, "
"smbus byte data not supported!\n");
@@ -821,6 +812,12 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file_in(new_client, 0);
device_create_file_in(new_client, 1);
device_create_file_in(new_client, 2);
@@ -847,6 +844,11 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+ERROR3:
+ i2c_detach_client(data->lm75[1]);
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[1]);
+ kfree(data->lm75[0]);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -857,21 +859,23 @@ ERROR0:
static int asb100_detach_client(struct i2c_client *client)
{
+ struct asb100_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "client deregistration failed; "
- "client not detached.\n");
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- if (i2c_get_clientdata(client)==NULL) {
- /* subclients */
+ /* main client */
+ if (data)
+ kfree(data);
+
+ /* subclient */
+ else
kfree(client);
- } else {
- /* main client */
- kfree(i2c_get_clientdata(client));
- }
return 0;
}
@@ -969,7 +973,7 @@ static void asb100_init_client(struct i2c_client *client)
vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index fca3fc1cef72..deb4d34c9539 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -23,8 +23,9 @@
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -40,9 +41,8 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
#define ATXP1_GPIO1MASK 0x0f
static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
-SENSORS_INSMOD_1(atxp1);
+I2C_CLIENT_INSMOD_1(atxp1);
static int atxp1_attach_adapter(struct i2c_adapter * adapter);
static int atxp1_detach_client(struct i2c_client * client);
@@ -59,6 +59,7 @@ static struct i2c_driver atxp1_driver = {
struct atxp1_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
unsigned long last_updated;
u8 valid;
@@ -252,7 +253,7 @@ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, &atxp1_detect);
+ return i2c_probe(adapter, &addr_data, &atxp1_detect);
};
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -295,7 +296,7 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Get VRM */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if ((data->vrm != 90) && (data->vrm != 91)) {
dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
@@ -317,6 +318,12 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
}
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_gpio1);
device_create_file(&new_client->dev, &dev_attr_gpio2);
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
@@ -326,6 +333,8 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -334,14 +343,17 @@ exit:
static int atxp1_detach_client(struct i2c_client * client)
{
+ struct atxp1_data * data = i2c_get_clientdata(client);
int err;
+ hwmon_device_unregister(data->class_dev);
+
err = i2c_detach_client(client);
if (err)
dev_err(&client->dev, "Failed to detach client.\n");
else
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return err;
};
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 5360d58804f6..b0199e063d0e 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -26,16 +26,16 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include "lm75.h"
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(ds1621);
+I2C_CLIENT_INSMOD_1(ds1621);
static int polarity = -1;
module_param(polarity, int, 0);
MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
@@ -71,6 +71,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
/* Each client has this additional data */
struct ds1621_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -179,10 +180,10 @@ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
{
- return i2c_detect(adapter, &addr_data, ds1621_detect);
+ return i2c_probe(adapter, &addr_data, ds1621_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int ds1621_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -250,6 +251,12 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
ds1621_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_alarms);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -259,6 +266,8 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
+ exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -267,15 +276,15 @@ int ds1621_detect(struct i2c_adapter *adapter, int address,
static int ds1621_detach_client(struct i2c_client *client)
{
+ struct ds1621_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index da411741c2c5..eef6061d786b 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -31,20 +31,20 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
*/
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(fscher);
+I2C_CLIENT_INSMOD_1(fscher);
/*
* The FSCHER registers
@@ -132,6 +132,7 @@ static struct i2c_driver fscher_driver = {
struct fscher_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -287,7 +288,7 @@ static int fscher_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, fscher_detect);
+ return i2c_probe(adapter, &addr_data, fscher_detect);
}
static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -341,6 +342,12 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
fscher_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file_revision(new_client);
device_create_file_alarms(new_client);
device_create_file_control(new_client);
@@ -360,6 +367,8 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -368,15 +377,15 @@ exit:
static int fscher_detach_client(struct i2c_client *client)
{
+ struct fscher_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 301ae98bd0ad..5fc77a5fed07 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -34,19 +34,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
*/
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(fscpos);
+I2C_CLIENT_INSMOD_1(fscpos);
/*
* The FSCPOS registers
@@ -113,6 +113,7 @@ static struct i2c_driver fscpos_driver = {
*/
struct fscpos_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* 0 until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -434,7 +435,7 @@ static int fscpos_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, fscpos_detect);
+ return i2c_probe(adapter, &addr_data, fscpos_detect);
}
int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -496,6 +497,12 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_event);
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
@@ -526,6 +533,8 @@ int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -534,14 +543,14 @@ exit:
static int fscpos_detach_client(struct i2c_client *client)
{
+ struct fscpos_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, client"
- " not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 6bedf729dcf5..256b9323c84b 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -41,14 +41,14 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80);
+I2C_CLIENT_INSMOD_2(gl518sm_r00, gl518sm_r80);
/* Many GL518 constants specified below */
@@ -117,6 +117,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* Each client has this additional data */
struct gl518_data {
struct i2c_client client;
+ struct class_device *class_dev;
enum chips type;
struct semaphore update_lock;
@@ -346,7 +347,7 @@ static int gl518_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, gl518_detect);
+ return i2c_probe(adapter, &addr_data, gl518_detect);
}
static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -419,6 +420,12 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
gl518_init_client((struct i2c_client *) new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -450,6 +457,8 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -477,16 +486,15 @@ static void gl518_init_client(struct i2c_client *client)
static int gl518_detach_client(struct i2c_client *client)
{
+ struct gl518_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
+ hwmon_device_unregister(data->class_dev);
- kfree(i2c_get_clientdata(client));
+ if ((err = i2c_detach_client(client)))
+ return err;
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 80ae8d30c2af..12fd757066fc 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -26,8 +26,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Type of the extra sensor */
static unsigned short extra_sensor_type;
@@ -36,10 +37,9 @@ MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=tempe
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(gl520sm);
+I2C_CLIENT_INSMOD_1(gl520sm);
/* Many GL520 constants specified below
One of the inputs can be configured as either temp or voltage.
@@ -120,6 +120,7 @@ static struct i2c_driver gl520_driver = {
/* Client data */
struct gl520_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until the following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -518,7 +519,7 @@ static int gl520_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, gl520_detect);
+ return i2c_probe(adapter, &addr_data, gl520_detect);
}
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -571,6 +572,12 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
gl520_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file_vid(new_client, 0);
device_create_file_in(new_client, 0);
@@ -592,6 +599,8 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -608,7 +617,7 @@ static void gl520_init_client(struct i2c_client *client)
conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
data->alarm_mask = 0xff;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if (extra_sensor_type == 1)
conf &= ~0x10;
@@ -639,15 +648,15 @@ static void gl520_init_client(struct i2c_client *client)
static int gl520_detach_client(struct i2c_client *client)
{
+ struct gl520_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
new file mode 100644
index 000000000000..7f0107613827
--- /dev/null
+++ b/drivers/hwmon/hdaps.c
@@ -0,0 +1,616 @@
+/*
+ * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
+ *
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ *
+ * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
+ * starting with the R40, T41, and X40. It provides a basic two-axis
+ * accelerometer and other data, such as the device's temperature.
+ *
+ * This driver is based on the document by Mark A. Smith available at
+ * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
+ * and error.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */
+#define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */
+
+#define HDAPS_PORT_STATE 0x1611 /* device state */
+#define HDAPS_PORT_YPOS 0x1612 /* y-axis position */
+#define HDAPS_PORT_XPOS 0x1614 /* x-axis position */
+#define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in celcius */
+#define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */
+#define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */
+#define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */
+#define HDAPS_PORT_UNKNOWN 0x161c /* what is this? */
+#define HDAPS_PORT_KMACT 0x161d /* keyboard or mouse activity */
+
+#define STATE_FRESH 0x50 /* accelerometer data is fresh */
+
+#define KEYBD_MASK 0x20 /* set if keyboard activity */
+#define MOUSE_MASK 0x40 /* set if mouse activity */
+#define KEYBD_ISSET(n) (!! (n & KEYBD_MASK)) /* keyboard used? */
+#define MOUSE_ISSET(n) (!! (n & MOUSE_MASK)) /* mouse used? */
+
+#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */
+#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */
+
+#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
+
+static struct timer_list hdaps_timer;
+static struct platform_device *pdev;
+static unsigned int hdaps_invert;
+static u8 km_activity;
+static int rest_x;
+static int rest_y;
+
+static DECLARE_MUTEX(hdaps_sem);
+
+/*
+ * __get_latch - Get the value from a given port. Callers must hold hdaps_sem.
+ */
+static inline u8 __get_latch(u16 port)
+{
+ return inb(port) & 0xff;
+}
+
+/*
+ * __check_latch - Check a port latch for a given value. Returns zero if the
+ * port contains the given value. Callers must hold hdaps_sem.
+ */
+static inline int __check_latch(u16 port, u8 val)
+{
+ if (__get_latch(port) == val)
+ return 0;
+ return -EINVAL;
+}
+
+/*
+ * __wait_latch - Wait up to 100us for a port latch to get a certain value,
+ * returning zero if the value is obtained. Callers must hold hdaps_sem.
+ */
+static int __wait_latch(u16 port, u8 val)
+{
+ unsigned int i;
+
+ for (i = 0; i < 20; i++) {
+ if (!__check_latch(port, val))
+ return 0;
+ udelay(5);
+ }
+
+ return -EIO;
+}
+
+/*
+ * __device_refresh - request a refresh from the accelerometer. Does not wait
+ * for refresh to complete. Callers must hold hdaps_sem.
+ */
+static void __device_refresh(void)
+{
+ udelay(200);
+ if (inb(0x1604) != STATE_FRESH) {
+ outb(0x11, 0x1610);
+ outb(0x01, 0x161f);
+ }
+}
+
+/*
+ * __device_refresh_sync - request a synchronous refresh from the
+ * accelerometer. We wait for the refresh to complete. Returns zero if
+ * successful and nonzero on error. Callers must hold hdaps_sem.
+ */
+static int __device_refresh_sync(void)
+{
+ __device_refresh();
+ return __wait_latch(0x1604, STATE_FRESH);
+}
+
+/*
+ * __device_complete - indicate to the accelerometer that we are done reading
+ * data, and then initiate an async refresh. Callers must hold hdaps_sem.
+ */
+static inline void __device_complete(void)
+{
+ inb(0x161f);
+ inb(0x1604);
+ __device_refresh();
+}
+
+/*
+ * hdaps_readb_one - reads a byte from a single I/O port, placing the value in
+ * the given pointer. Returns zero on success or a negative error on failure.
+ * Can sleep.
+ */
+static int hdaps_readb_one(unsigned int port, u8 *val)
+{
+ int ret;
+
+ down(&hdaps_sem);
+
+ /* do a sync refresh -- we need to be sure that we read fresh data */
+ ret = __device_refresh_sync();
+ if (ret)
+ goto out;
+
+ *val = inb(port);
+ __device_complete();
+
+out:
+ up(&hdaps_sem);
+ return ret;
+}
+
+/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */
+static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
+ int *x, int *y)
+{
+ /* do a sync refresh -- we need to be sure that we read fresh data */
+ if (__device_refresh_sync())
+ return -EIO;
+
+ *y = inw(port2);
+ *x = inw(port1);
+ km_activity = inb(HDAPS_PORT_KMACT);
+ __device_complete();
+
+ /* if hdaps_invert is set, negate the two values */
+ if (hdaps_invert) {
+ *x = -*x;
+ *y = -*y;
+ }
+
+ return 0;
+}
+
+/*
+ * hdaps_read_pair - reads the values from a pair of ports, placing the values
+ * in the given pointers. Returns zero on success. Can sleep.
+ */
+static int hdaps_read_pair(unsigned int port1, unsigned int port2,
+ int *val1, int *val2)
+{
+ int ret;
+
+ down(&hdaps_sem);
+ ret = __hdaps_read_pair(port1, port2, val1, val2);
+ up(&hdaps_sem);
+
+ return ret;
+}
+
+/*
+ * hdaps_device_init - initialize the accelerometer. Returns zero on success
+ * and negative error code on failure. Can sleep.
+ */
+static int hdaps_device_init(void)
+{
+ int total, ret = -ENXIO;
+
+ down(&hdaps_sem);
+
+ outb(0x13, 0x1610);
+ outb(0x01, 0x161f);
+ if (__wait_latch(0x161f, 0x00))
+ goto out;
+
+ /*
+ * Most ThinkPads return 0x01.
+ *
+ * Others--namely the R50p, T41p, and T42p--return 0x03. These laptops
+ * have "inverted" axises.
+ *
+ * The 0x02 value occurs when the chip has been previously initialized.
+ */
+ if (__check_latch(0x1611, 0x03) &&
+ __check_latch(0x1611, 0x02) &&
+ __check_latch(0x1611, 0x01))
+ goto out;
+
+ printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
+ __get_latch(0x1611));
+
+ outb(0x17, 0x1610);
+ outb(0x81, 0x1611);
+ outb(0x01, 0x161f);
+ if (__wait_latch(0x161f, 0x00))
+ goto out;
+ if (__wait_latch(0x1611, 0x00))
+ goto out;
+ if (__wait_latch(0x1612, 0x60))
+ goto out;
+ if (__wait_latch(0x1613, 0x00))
+ goto out;
+ outb(0x14, 0x1610);
+ outb(0x01, 0x1611);
+ outb(0x01, 0x161f);
+ if (__wait_latch(0x161f, 0x00))
+ goto out;
+ outb(0x10, 0x1610);
+ outb(0xc8, 0x1611);
+ outb(0x00, 0x1612);
+ outb(0x02, 0x1613);
+ outb(0x01, 0x161f);
+ if (__wait_latch(0x161f, 0x00))
+ goto out;
+ if (__device_refresh_sync())
+ goto out;
+ if (__wait_latch(0x1611, 0x00))
+ goto out;
+
+ /* we have done our dance, now let's wait for the applause */
+ for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+ int x, y;
+
+ /* a read of the device helps push it into action */
+ __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
+ if (!__wait_latch(0x1611, 0x02)) {
+ ret = 0;
+ break;
+ }
+
+ msleep(INIT_WAIT_MSECS);
+ }
+
+out:
+ up(&hdaps_sem);
+ return ret;
+}
+
+
+/* Device model stuff */
+
+static int hdaps_probe(struct device *dev)
+{
+ int ret;
+
+ ret = hdaps_device_init();
+ if (ret)
+ return ret;
+
+ printk(KERN_INFO "hdaps: device successfully initialized.\n");
+ return 0;
+}
+
+static int hdaps_resume(struct device *dev, u32 level)
+{
+ if (level == RESUME_ENABLE)
+ return hdaps_device_init();
+ return 0;
+}
+
+static struct device_driver hdaps_driver = {
+ .name = "hdaps",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ .probe = hdaps_probe,
+ .resume = hdaps_resume
+};
+
+/* Input class stuff */
+
+static struct input_dev hdaps_idev = {
+ .name = "hdaps",
+ .evbit = { BIT(EV_ABS) },
+ .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
+ .absmin = { [ABS_X] = -256, [ABS_Y] = -256 },
+ .absmax = { [ABS_X] = 256, [ABS_Y] = 256 },
+ .absfuzz = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ },
+ .absflat = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ },
+};
+
+/*
+ * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem.
+ */
+static void hdaps_calibrate(void)
+{
+ __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
+}
+
+static void hdaps_mousedev_poll(unsigned long unused)
+{
+ int x, y;
+
+ /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
+ if (down_trylock(&hdaps_sem)) {
+ mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
+ return;
+ }
+
+ if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
+ goto out;
+
+ input_report_abs(&hdaps_idev, ABS_X, x - rest_x);
+ input_report_abs(&hdaps_idev, ABS_Y, y - rest_y);
+ input_sync(&hdaps_idev);
+
+ mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
+
+out:
+ up(&hdaps_sem);
+}
+
+
+/* Sysfs Files */
+
+static ssize_t hdaps_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret, x, y;
+
+ ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_variance_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret, x, y;
+
+ ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "(%d,%d)\n", x, y);
+}
+
+static ssize_t hdaps_temp1_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 temp;
+ int ret;
+
+ ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_temp2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 temp;
+ int ret;
+
+ ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%u\n", temp);
+}
+
+static ssize_t hdaps_keyboard_activity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));
+}
+
+static ssize_t hdaps_mouse_activity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));
+}
+
+static ssize_t hdaps_calibrate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t hdaps_calibrate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ down(&hdaps_sem);
+ hdaps_calibrate();
+ up(&hdaps_sem);
+
+ return count;
+}
+
+static ssize_t hdaps_invert_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", hdaps_invert);
+}
+
+static ssize_t hdaps_invert_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int invert;
+
+ if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))
+ return -EINVAL;
+
+ hdaps_invert = invert;
+ hdaps_calibrate();
+
+ return count;
+}
+
+static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
+static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);
+static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
+static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);
+static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
+static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
+static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
+static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
+
+static struct attribute *hdaps_attributes[] = {
+ &dev_attr_position.attr,
+ &dev_attr_variance.attr,
+ &dev_attr_temp1.attr,
+ &dev_attr_temp2.attr,
+ &dev_attr_keyboard_activity.attr,
+ &dev_attr_mouse_activity.attr,
+ &dev_attr_calibrate.attr,
+ &dev_attr_invert.attr,
+ NULL,
+};
+
+static struct attribute_group hdaps_attribute_group = {
+ .attrs = hdaps_attributes,
+};
+
+
+/* Module stuff */
+
+/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */
+static int hdaps_dmi_match(struct dmi_system_id *id)
+{
+ printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
+ return 1;
+}
+
+/* hdaps_dmi_match_invert - found an inverted match. */
+static int hdaps_dmi_match_invert(struct dmi_system_id *id)
+{
+ hdaps_invert = 1;
+ printk(KERN_INFO "hdaps: inverting axis readings.\n");
+ return hdaps_dmi_match(id);
+}
+
+#define HDAPS_DMI_MATCH_NORMAL(model) { \
+ .ident = "IBM " model, \
+ .callback = hdaps_dmi_match, \
+ .matches = { \
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_VERSION, model) \
+ } \
+}
+
+#define HDAPS_DMI_MATCH_INVERT(model) { \
+ .ident = "IBM " model, \
+ .callback = hdaps_dmi_match_invert, \
+ .matches = { \
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \
+ DMI_MATCH(DMI_PRODUCT_VERSION, model) \
+ } \
+}
+
+static int __init hdaps_init(void)
+{
+ int ret;
+
+ /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */
+ struct dmi_system_id hdaps_whitelist[] = {
+ HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"),
+ HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),
+ HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"),
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
+ { .ident = NULL }
+ };
+
+ if (!dmi_check_system(hdaps_whitelist)) {
+ printk(KERN_WARNING "hdaps: supported laptop not found!\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = driver_register(&hdaps_driver);
+ if (ret)
+ goto out_region;
+
+ pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_driver;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
+ if (ret)
+ goto out_device;
+
+ /* initial calibrate for the input device */
+ hdaps_calibrate();
+
+ /* initialize the input class */
+ hdaps_idev.dev = &pdev->dev;
+ input_register_device(&hdaps_idev);
+
+ /* start up our timer for the input device */
+ init_timer(&hdaps_timer);
+ hdaps_timer.function = hdaps_mousedev_poll;
+ hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD;
+ add_timer(&hdaps_timer);
+
+ printk(KERN_INFO "hdaps: driver successfully loaded.\n");
+ return 0;
+
+out_device:
+ platform_device_unregister(pdev);
+out_driver:
+ driver_unregister(&hdaps_driver);
+out_region:
+ release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+out:
+ printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
+ return ret;
+}
+
+static void __exit hdaps_exit(void)
+{
+ del_timer_sync(&hdaps_timer);
+ input_unregister_device(&hdaps_idev);
+ sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
+ platform_device_unregister(pdev);
+ driver_unregister(&hdaps_driver);
+ release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
+
+ printk(KERN_INFO "hdaps: driver unloaded.\n");
+}
+
+module_init(hdaps_init);
+module_exit(hdaps_exit);
+
+module_param_named(invert, hdaps_invert, bool, 0);
+MODULE_PARM_DESC(invert, "invert data along each axis");
+
+MODULE_AUTHOR("Robert Love");
+MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
new file mode 100644
index 000000000000..312769ad4dab
--- /dev/null
+++ b/drivers/hwmon/hwmon-vid.c
@@ -0,0 +1,189 @@
+/*
+ hwmon-vid.c - VID/VRM/VRD voltage conversions
+
+ Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
+
+ Partly imported from i2c-vid.h of the lm_sensors project
+ Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+ With assistance from Trent Piepho <xyzzy@speakeasy.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/hwmon-vid.h>
+
+/*
+ Common code for decoding VID pins.
+
+ References:
+
+ For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
+ available at http://developer.intel.com/.
+
+ For VRD 10.0 and up, "VRD x.y Design Guide",
+ available at http://developer.intel.com/.
+
+ AMD Opteron processors don't follow the Intel specifications.
+ I'm going to "make up" 2.4 as the spec number for the Opterons.
+ No good reason just a mnemonic for the 24x Opteron processor
+ series.
+
+ Opteron VID encoding is:
+ 00000 = 1.550 V
+ 00001 = 1.525 V
+ . . . .
+ 11110 = 0.800 V
+ 11111 = 0.000 V (off)
+*/
+
+/* vrm is the VRM/VRD document version multiplied by 10.
+ val is the 4-, 5- or 6-bit VID code.
+ Returned value is in mV to avoid floating point in the kernel. */
+int vid_from_reg(int val, int vrm)
+{
+ int vid;
+
+ switch(vrm) {
+
+ case 0:
+ return 0;
+
+ case 100: /* VRD 10.0 */
+ if((val & 0x1f) == 0x1f)
+ return 0;
+ if((val & 0x1f) <= 0x09 || val == 0x0a)
+ vid = 10875 - (val & 0x1f) * 250;
+ else
+ vid = 18625 - (val & 0x1f) * 250;
+ if(val & 0x20)
+ vid -= 125;
+ vid /= 10; /* only return 3 dec. places for now */
+ return vid;
+
+ case 24: /* Opteron processor */
+ return(val == 0x1f ? 0 : 1550 - val * 25);
+
+ case 91: /* VRM 9.1 */
+ case 90: /* VRM 9.0 */
+ return(val == 0x1f ? 0 :
+ 1850 - val * 25);
+
+ case 85: /* VRM 8.5 */
+ return((val & 0x10 ? 25 : 0) +
+ ((val & 0x0f) > 0x04 ? 2050 : 1250) -
+ ((val & 0x0f) * 50));
+
+ case 84: /* VRM 8.4 */
+ val &= 0x0f;
+ /* fall through */
+ default: /* VRM 8.2 */
+ return(val == 0x1f ? 0 :
+ val & 0x10 ? 5100 - (val) * 100 :
+ 2050 - (val) * 50);
+ }
+}
+
+
+/*
+ After this point is the code to automatically determine which
+ VRM/VRD specification should be used depending on the CPU.
+*/
+
+struct vrm_model {
+ u8 vendor;
+ u8 eff_family;
+ u8 eff_model;
+ int vrm_type;
+};
+
+#define ANY 0xFF
+
+#ifdef CONFIG_X86
+
+static struct vrm_model vrm_models[] = {
+ {X86_VENDOR_AMD, 0x6, ANY, 90}, /* Athlon Duron etc */
+ {X86_VENDOR_AMD, 0xF, ANY, 24}, /* Athlon 64, Opteron */
+ {X86_VENDOR_INTEL, 0x6, 0x9, 85}, /* 0.13um too */
+ {X86_VENDOR_INTEL, 0x6, 0xB, 85}, /* Tualatin */
+ {X86_VENDOR_INTEL, 0x6, ANY, 82}, /* any P6 */
+ {X86_VENDOR_INTEL, 0x7, ANY, 0}, /* Itanium */
+ {X86_VENDOR_INTEL, 0xF, 0x0, 90}, /* P4 */
+ {X86_VENDOR_INTEL, 0xF, 0x1, 90}, /* P4 Willamette */
+ {X86_VENDOR_INTEL, 0xF, 0x2, 90}, /* P4 Northwood */
+ {X86_VENDOR_INTEL, 0xF, 0x3, 100}, /* P4 Prescott */
+ {X86_VENDOR_INTEL, 0xF, 0x4, 100}, /* P4 Prescott */
+ {X86_VENDOR_INTEL, 0x10,ANY, 0}, /* Itanium 2 */
+ {X86_VENDOR_UNKNOWN, ANY, ANY, 0} /* stop here */
+};
+
+static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
+{
+ int i = 0;
+
+ while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
+ if (vrm_models[i].vendor==vendor)
+ if ((vrm_models[i].eff_family==eff_family)
+ && ((vrm_models[i].eff_model==eff_model) ||
+ (vrm_models[i].eff_model==ANY)))
+ return vrm_models[i].vrm_type;
+ i++;
+ }
+
+ return 0;
+}
+
+int vid_which_vrm(void)
+{
+ struct cpuinfo_x86 *c = cpu_data;
+ u32 eax;
+ u8 eff_family, eff_model;
+ int vrm_ret;
+
+ if (c->x86 < 6) /* Any CPU with family lower than 6 */
+ return 0; /* doesn't have VID and/or CPUID */
+
+ eax = cpuid_eax(1);
+ eff_family = ((eax & 0x00000F00)>>8);
+ eff_model = ((eax & 0x000000F0)>>4);
+ if (eff_family == 0xF) { /* use extended model & family */
+ eff_family += ((eax & 0x00F00000)>>20);
+ eff_model += ((eax & 0x000F0000)>>16)<<4;
+ }
+ vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
+ if (vrm_ret == 0)
+ printk(KERN_INFO "hwmon-vid: Unknown VRM version of your "
+ "x86 CPU\n");
+ return vrm_ret;
+}
+
+/* and now something completely different for the non-x86 world */
+#else
+int vid_which_vrm(void)
+{
+ printk(KERN_INFO "hwmon-vid: Unknown VRM version of your CPU\n");
+ return 0;
+}
+#endif
+
+EXPORT_SYMBOL(vid_from_reg);
+EXPORT_SYMBOL(vid_which_vrm);
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+
+MODULE_DESCRIPTION("hwmon-vid driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
new file mode 100644
index 000000000000..9b41c9bd805f
--- /dev/null
+++ b/drivers/hwmon/hwmon.c
@@ -0,0 +1,98 @@
+/*
+ hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
+
+ This file defines the sysfs class "hwmon", for use by sensors drivers.
+
+ Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/hwmon.h>
+
+#define HWMON_ID_PREFIX "hwmon"
+#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
+
+static struct class *hwmon_class;
+
+static DEFINE_IDR(hwmon_idr);
+
+/**
+ * hwmon_device_register - register w/ hwmon sysfs class
+ * @dev: the device to register
+ *
+ * hwmon_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct class_device *hwmon_device_register(struct device *dev)
+{
+ struct class_device *cdev;
+ int id;
+
+ if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)
+ return ERR_PTR(-ENOMEM);
+
+ if (idr_get_new(&hwmon_idr, NULL, &id) < 0)
+ return ERR_PTR(-ENOMEM);
+
+ id = id & MAX_ID_MASK;
+ cdev = class_device_create(hwmon_class, MKDEV(0,0), dev,
+ HWMON_ID_FORMAT, id);
+
+ if (IS_ERR(cdev))
+ idr_remove(&hwmon_idr, id);
+
+ return cdev;
+}
+
+/**
+ * hwmon_device_unregister - removes the previously registered class device
+ *
+ * @cdev: the class device to destroy
+ */
+void hwmon_device_unregister(struct class_device *cdev)
+{
+ int id;
+
+ if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) {
+ class_device_unregister(cdev);
+ idr_remove(&hwmon_idr, id);
+ } else
+ dev_dbg(cdev->dev,
+ "hwmon_device_unregister() failed: bad class ID!\n");
+}
+
+static int __init hwmon_init(void)
+{
+ hwmon_class = class_create(THIS_MODULE, "hwmon");
+ if (IS_ERR(hwmon_class)) {
+ printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
+ return PTR_ERR(hwmon_class);
+ }
+ return 0;
+}
+
+static void __exit hwmon_exit(void)
+{
+ class_destroy(hwmon_class);
+}
+
+module_init(hwmon_init);
+module_exit(hwmon_exit);
+
+EXPORT_SYMBOL_GPL(hwmon_device_register);
+EXPORT_SYMBOL_GPL(hwmon_device_unregister);
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index db20c9e47393..53cc2b6d6385 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -36,19 +36,21 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_2(it87, it8712);
+I2C_CLIENT_INSMOD_2(it87, it8712);
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
@@ -192,6 +194,7 @@ static int DIV_TO_REG(int val)
allocated. */
struct it87_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -218,7 +221,7 @@ struct it87_data {
static int it87_attach_adapter(struct i2c_adapter *adapter);
-static int it87_find(int *address);
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter);
static int it87_detect(struct i2c_adapter *adapter, int address, int kind);
static int it87_detach_client(struct i2c_client *client);
@@ -239,6 +242,14 @@ static struct i2c_driver it87_driver = {
.detach_client = it87_detach_client,
};
+static struct i2c_driver it87_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "it87-isa",
+ .attach_adapter = it87_isa_attach_adapter,
+ .detach_client = it87_detach_client,
+};
+
+
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -686,11 +697,16 @@ static int it87_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, it87_detect);
+ return i2c_probe(adapter, &addr_data, it87_detect);
}
-/* SuperIO detection - will change normal_isa[0] if a chip is found */
-static int it87_find(int *address)
+static int it87_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return it87_detect(adapter, isa_address, -1);
+}
+
+/* SuperIO detection - will change isa_address if a chip is found */
+static int __init it87_find(int *address)
{
int err = -ENODEV;
@@ -721,7 +737,7 @@ exit:
return err;
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int it87_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -738,7 +754,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
/* Reserve the ISA region */
if (is_isa)
- if (!request_region(address, IT87_EXTENT, it87_driver.name))
+ if (!request_region(address, IT87_EXTENT, it87_isa_driver.name))
goto ERROR0;
/* Probe whether there is anything available on this address. Already
@@ -784,7 +800,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &it87_driver;
+ new_client->driver = is_isa ? &it87_isa_driver : &it87_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -840,6 +856,12 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
it87_init_client(new_client, data);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
@@ -897,13 +919,15 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
}
if (data->type == it8712) {
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
device_create_file_vrm(new_client);
device_create_file_vid(new_client);
}
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -915,17 +939,17 @@ ERROR0:
static int it87_detach_client(struct i2c_client *client)
{
+ struct it87_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
if(i2c_is_isa_client(client))
release_region(client->addr, IT87_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1158,16 +1182,28 @@ static struct it87_data *it87_update_device(struct device *dev)
static int __init sm_it87_init(void)
{
- int addr;
+ int addr, res;
if (!it87_find(&addr)) {
- normal_isa[0] = addr;
+ isa_address = addr;
+ }
+
+ res = i2c_add_driver(&it87_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&it87_isa_driver);
+ if (res) {
+ i2c_del_driver(&it87_driver);
+ return res;
}
- return i2c_add_driver(&it87_driver);
+
+ return 0;
}
static void __exit sm_it87_exit(void)
{
+ i2c_isa_del_driver(&it87_isa_driver);
i2c_del_driver(&it87_driver);
}
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 7c6f9ea5a254..be5c7095ecbb 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -42,8 +42,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -51,13 +52,12 @@
*/
static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm63);
+I2C_CLIENT_INSMOD_1(lm63);
/*
* The LM63 registers
@@ -152,6 +152,7 @@ static struct i2c_driver lm63_driver = {
struct lm63_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -358,7 +359,7 @@ static int lm63_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm63_detect);
+ return i2c_probe(adapter, &addr_data, lm63_detect);
}
/*
@@ -437,6 +438,12 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
lm63_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
if (data->config & 0x04) { /* tachometer enabled */
device_create_file(&new_client->dev,
&sensor_dev_attr_fan1_input.dev_attr);
@@ -462,6 +469,8 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -505,15 +514,15 @@ static void lm63_init_client(struct i2c_client *client)
static int lm63_detach_client(struct i2c_client *client)
{
+ struct lm63_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 5be164ed278e..9a3ebdf583f4 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -23,17 +23,17 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include "lm75.h"
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm75);
+I2C_CLIENT_INSMOD_1(lm75);
/* Many LM75 constants specified below */
@@ -46,6 +46,7 @@ SENSORS_INSMOD_1(lm75);
/* Each client has this additional data */
struct lm75_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -107,10 +108,10 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm75_detect);
+ return i2c_probe(adapter, &addr_data, lm75_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -119,16 +120,6 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
int err = 0;
const char *name = "";
- /* Make sure we aren't probing the ISA bus!! This is just a safety check
- at this moment; i2c_detect really won't call us. */
-#ifdef DEBUG
- if (i2c_is_isa_adapter(adapter)) {
- dev_dbg(&adapter->dev,
- "lm75_detect called for an ISA bus adapter?!?\n");
- goto exit;
- }
-#endif
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
goto exit;
@@ -208,12 +199,20 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
lm75_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -222,8 +221,10 @@ exit:
static int lm75_detach_client(struct i2c_client *client)
{
+ struct lm75_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -251,8 +252,12 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
static void lm75_init_client(struct i2c_client *client)
{
- /* Initialize the LM75 chip */
- lm75_write_value(client, LM75_REG_CONF, 0);
+ int reg;
+
+ /* Enable if in shutdown mode */
+ reg = lm75_read_value(client, LM75_REG_CONF);
+ if (reg >= 0 && (reg & 0x01))
+ lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
}
static struct lm75_data *lm75_update_device(struct device *dev)
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index 63e3f2fb4c21..af7dc650ee15 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -25,7 +25,7 @@
which contains this code, we don't worry about the wasted space.
*/
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
/* straight from the datasheet */
#define LM75_TEMP_MIN (-55000)
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index b98f44952997..866eab96a6f6 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -30,15 +30,14 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm77);
+I2C_CLIENT_INSMOD_1(lm77);
/* The LM77 registers */
#define LM77_REG_TEMP 0x00
@@ -51,6 +50,7 @@ SENSORS_INSMOD_1(lm77);
/* Each client has this additional data */
struct lm77_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
@@ -208,10 +208,10 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm77_detect);
+ return i2c_probe(adapter, &addr_data, lm77_detect);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
@@ -317,6 +317,12 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
lm77_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
@@ -327,6 +333,8 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -335,8 +343,10 @@ exit:
static int lm77_detach_client(struct i2c_client *client)
{
+ struct lm77_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 29241469dcba..f6730dc3573b 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -23,7 +23,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
/* Addresses to scan */
@@ -31,10 +34,10 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_3(lm78, lm78j, lm79);
+I2C_CLIENT_INSMOD_2(lm78, lm79);
/* Many LM78 constants specified below */
@@ -104,13 +107,6 @@ static inline int TEMP_FROM_REG(s8 val)
return val * 1000;
}
-/* VID: mV
- REG: (see doc/vid) */
-static inline int VID_FROM_REG(u8 val)
-{
- return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50;
-}
-
#define DIV_FROM_REG(val) (1 << (val))
/* There are some complications in a module like this. First off, LM78 chips
@@ -134,6 +130,7 @@ static inline int VID_FROM_REG(u8 val)
allocated. */
struct lm78_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -156,6 +153,7 @@ struct lm78_data {
static int lm78_attach_adapter(struct i2c_adapter *adapter);
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter);
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind);
static int lm78_detach_client(struct i2c_client *client);
@@ -174,6 +172,14 @@ static struct i2c_driver lm78_driver = {
.detach_client = lm78_detach_client,
};
+static struct i2c_driver lm78_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "lm78-isa",
+ .attach_adapter = lm78_isa_attach_adapter,
+ .detach_client = lm78_detach_client,
+};
+
+
/* 7 Voltages */
static ssize_t show_in(struct device *dev, char *buf, int nr)
{
@@ -445,7 +451,7 @@ static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL);
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", VID_FROM_REG(data->vid));
+ return sprintf(buf, "%d\n", vid_from_reg(82, data->vid));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
@@ -465,10 +471,15 @@ static int lm78_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm78_detect);
+ return i2c_probe(adapter, &addr_data, lm78_detect);
+}
+
+static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return lm78_detect(adapter, isa_address, -1);
}
-/* This function is called by i2c_detect */
+/* This function is called by i2c_probe */
int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i, err;
@@ -485,7 +496,8 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
/* Reserve the ISA region */
if (is_isa)
- if (!request_region(address, LM78_EXTENT, lm78_driver.name)) {
+ if (!request_region(address, LM78_EXTENT,
+ lm78_isa_driver.name)) {
err = -EBUSY;
goto ERROR0;
}
@@ -540,7 +552,7 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &lm78_driver;
+ new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -559,10 +571,9 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
/* Determine the chip type. */
if (kind <= 0) {
i = lm78_read_value(new_client, LM78_REG_CHIPID);
- if (i == 0x00 || i == 0x20)
+ if (i == 0x00 || i == 0x20 /* LM78 */
+ || i == 0x40) /* LM78-J */
kind = lm78;
- else if (i == 0x40)
- kind = lm78j;
else if ((i & 0xfe) == 0xc0)
kind = lm79;
else {
@@ -578,8 +589,6 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind == lm78) {
client_name = "lm78";
- } else if (kind == lm78j) {
- client_name = "lm78-j";
} else if (kind == lm79) {
client_name = "lm79";
}
@@ -605,6 +614,12 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -643,6 +658,8 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -654,18 +671,18 @@ ERROR0:
static int lm78_detach_client(struct i2c_client *client)
{
+ struct lm78_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
if(i2c_is_isa_client(client))
release_region(client->addr, LM78_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -777,18 +794,31 @@ static struct lm78_data *lm78_update_device(struct device *dev)
static int __init sm_lm78_init(void)
{
- return i2c_add_driver(&lm78_driver);
+ int res;
+
+ res = i2c_add_driver(&lm78_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&lm78_isa_driver);
+ if (res) {
+ i2c_del_driver(&lm78_driver);
+ return res;
+ }
+
+ return 0;
}
static void __exit sm_lm78_exit(void)
{
+ i2c_isa_del_driver(&lm78_isa_driver);
i2c_del_driver(&lm78_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
-MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
+MODULE_DESCRIPTION("LM78/LM79 driver");
MODULE_LICENSE("GPL");
module_init(sm_lm78_init);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 8100595feb44..83af8b3a0cac 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -26,15 +26,15 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c,
0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm80);
+I2C_CLIENT_INSMOD_1(lm80);
/* Many LM80 constants specified below */
@@ -107,6 +107,7 @@ static inline long TEMP_FROM_REG(u16 temp)
struct lm80_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -389,7 +390,7 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm80_detect);
+ return i2c_probe(adapter, &addr_data, lm80_detect);
}
int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -451,6 +452,12 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in1_min);
device_create_file(&new_client->dev, &dev_attr_in2_min);
@@ -487,6 +494,8 @@ int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
exit:
@@ -495,15 +504,15 @@ exit:
static int lm80_detach_client(struct i2c_client *client)
{
+ struct lm80_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index a49008b444c8..d74b2c20c719 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -32,8 +32,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -45,13 +46,12 @@ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm83);
+I2C_CLIENT_INSMOD_1(lm83);
/*
* The LM83 registers
@@ -138,6 +138,7 @@ static struct i2c_driver lm83_driver = {
struct lm83_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -212,7 +213,7 @@ static int lm83_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm83_detect);
+ return i2c_probe(adapter, &addr_data, lm83_detect);
}
/*
@@ -312,6 +313,12 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
*/
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_create_file(&new_client->dev,
@@ -340,6 +347,8 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -348,15 +357,15 @@ exit:
static int lm83_detach_client(struct i2c_client *client)
{
+ struct lm83_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index b4d7fd418264..ab214df9624b 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -28,15 +28,15 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
/* The LM85 registers */
@@ -281,15 +281,6 @@ static int ZONE_TO_REG( int zone )
#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)
-/* i2c-vid.h defines vid_from_reg() */
-#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
-
-/* Unlike some other drivers we DO NOT set initial limits. Use
- * the config file to set limits. Some users have reported
- * motherboards shutting down when we set limits in a previous
- * version of the driver.
- */
-
/* Chip sampling rates
*
* Some sensors are not updated more frequently than once per second
@@ -339,6 +330,7 @@ struct lm85_autofan {
struct lm85_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -1019,7 +1011,7 @@ int lm85_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm85_detect);
+ return i2c_probe(adapter, &addr_data, lm85_detect);
}
int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1031,11 +1023,6 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
int err = 0;
const char *type_name = "";
- if (i2c_is_isa_adapter(adapter)) {
- /* This chip has no ISA interface */
- goto ERROR0 ;
- };
-
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
@@ -1160,12 +1147,18 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
goto ERROR1;
/* Set the VRM version */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
/* Initialize the LM85 chip */
lm85_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR2;
+ }
+
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan2_input);
device_create_file(&new_client->dev, &dev_attr_fan3_input);
@@ -1235,6 +1228,8 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
return 0;
/* Error out and cleanup code */
+ ERROR2:
+ i2c_detach_client(new_client);
ERROR1:
kfree(data);
ERROR0:
@@ -1243,8 +1238,10 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
int lm85_detach_client(struct i2c_client *client)
{
+ struct lm85_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
i2c_detach_client(client);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 1921ed1af182..dca996de4c33 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -57,8 +57,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -66,13 +67,12 @@
*/
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(lm87);
+I2C_CLIENT_INSMOD_1(lm87);
/*
* The LM87 registers
@@ -175,6 +175,7 @@ static struct i2c_driver lm87_driver = {
struct lm87_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -537,7 +538,7 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm87_detect);
+ return i2c_probe(adapter, &addr_data, lm87_detect);
}
/*
@@ -608,6 +609,12 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
data->in_scale[7] = 1875;
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in1_min);
device_create_file(&new_client->dev, &dev_attr_in1_max);
@@ -673,6 +680,8 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -685,7 +694,7 @@ static void lm87_init_client(struct i2c_client *client)
u8 config;
data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
config = lm87_read_value(client, LM87_REG_CONFIG);
if (!(config & 0x01)) {
@@ -719,15 +728,15 @@ static void lm87_init_client(struct i2c_client *client)
static int lm87_detach_client(struct i2c_client *client)
{
+ struct lm87_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index a67dcadf7cb0..14de05fcd431 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -75,8 +75,9 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/*
* Addresses to scan
@@ -89,13 +90,12 @@
*/
static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
/*
* The LM90 registers
@@ -200,6 +200,7 @@ static struct i2c_driver lm90_driver = {
struct lm90_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -352,7 +353,7 @@ static int lm90_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm90_detect);
+ return i2c_probe(adapter, &addr_data, lm90_detect);
}
/*
@@ -500,6 +501,12 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
lm90_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_create_file(&new_client->dev,
@@ -524,6 +531,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -547,15 +556,15 @@ static void lm90_init_client(struct i2c_client *client)
static int lm90_detach_client(struct i2c_client *client)
{
+ struct lm90_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 215c8e40ffdd..647b7c7cd575 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -44,17 +44,16 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* The LM92 and MAX6635 have 2 two-state pins for address selection,
resulting in 4 possible addresses. */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(lm92);
+I2C_CLIENT_INSMOD_1(lm92);
/* The LM92 registers */
#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */
@@ -96,6 +95,7 @@ static struct i2c_driver lm92_driver;
/* Client data (each client gets its own) */
struct lm92_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -359,6 +359,12 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
lm92_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
@@ -370,6 +376,8 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -380,20 +388,20 @@ static int lm92_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, lm92_detect);
+ return i2c_probe(adapter, &addr_data, lm92_detect);
}
static int lm92_detach_client(struct i2c_client *client)
{
+ struct lm92_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 3c159f1d49ee..16bf71f3a04d 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -31,20 +31,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-
+#include <linux/hwmon.h>
+#include <linux/err.h>
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(max1619);
+I2C_CLIENT_INSMOD_1(max1619);
/*
* The MAX1619 registers
@@ -104,6 +103,7 @@ static struct i2c_driver max1619_driver = {
struct max1619_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -179,7 +179,7 @@ static int max1619_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, max1619_detect);
+ return i2c_probe(adapter, &addr_data, max1619_detect);
}
/*
@@ -275,6 +275,12 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
max1619_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp2_input);
device_create_file(&new_client->dev, &dev_attr_temp2_min);
@@ -285,6 +291,8 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -308,15 +316,15 @@ static void max1619_init_client(struct i2c_client *client)
static int max1619_detach_client(struct i2c_client *client)
{
+ struct max1619_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index fa4032d53b79..cf2a35799c7c 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -38,23 +38,19 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{ NULL }};
static u8 devid;
-static unsigned int extra_isa[3];
+static unsigned short address;
+static unsigned short extra_isa[3];
static u8 confreg[4];
enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .forces = forces,
-};
static int init = 1;
module_param(init, int, 0);
@@ -186,6 +182,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
struct pc87360_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
@@ -224,8 +221,7 @@ struct pc87360_data {
* Functions declaration
*/
-static int pc87360_attach_adapter(struct i2c_adapter *adapter);
-static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pc87360_detect(struct i2c_adapter *adapter);
static int pc87360_detach_client(struct i2c_client *client);
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
@@ -242,8 +238,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev);
static struct i2c_driver pc87360_driver = {
.owner = THIS_MODULE,
.name = "pc87360",
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = pc87360_attach_adapter,
+ .attach_adapter = pc87360_detect,
.detach_client = pc87360_detach_client,
};
@@ -251,168 +246,178 @@ static struct i2c_driver pc87360_driver = {
* Sysfs stuff
*/
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index],
+ FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index],
+ FAN_DIV_FROM_REG(data->fan_status[attr->index])));
+}
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ FAN_DIV_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t show_fan_status(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ FAN_STATUS_FROM_REG(data->fan_status[attr->index]));
+}
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
long fan_min = simple_strtol(buf, NULL, 10);
down(&data->update_lock);
- fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
+ fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index]));
/* If it wouldn't fit, change clock divisor */
while (fan_min > 255
- && (data->fan_status[nr] & 0x60) != 0x60) {
+ && (data->fan_status[attr->index] & 0x60) != 0x60) {
fan_min >>= 1;
- data->fan[nr] >>= 1;
- data->fan_status[nr] += 0x20;
+ data->fan[attr->index] >>= 1;
+ data->fan_status[attr->index] += 0x20;
}
- data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr),
- data->fan_min[nr]);
+ data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min;
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(attr->index),
+ data->fan_min[attr->index]);
/* Write new divider, preserve alarm bits */
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
- data->fan_status[nr] & 0xF9);
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index),
+ data->fan_status[attr->index] & 0xF9);
up(&data->update_lock);
return count;
}
#define show_and_set_fan(offset) \
-static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \
- FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \
- FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
-} \
-static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- FAN_DIV_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \
-} \
-static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset-1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
- show_fan##offset##_input, NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
- show_fan##offset##_min, set_fan##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
- show_fan##offset##_div, NULL); \
-static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
- show_fan##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
+ show_fan_min, set_fan_min, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+ show_fan_div, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
+ show_fan_status, NULL, offset-1);
show_and_set_fan(1)
show_and_set_fan(2)
show_and_set_fan(3)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n",
+ PWM_FROM_REG(data->pwm[attr->index],
+ FAN_CONFIG_INVERT(data->fan_conf,
+ attr->index)));
+}
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->pwm[attr->index] = PWM_TO_REG(val,
+ FAN_CONFIG_INVERT(data->fan_conf, attr->index));
+ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index),
+ data->pwm[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_pwm(offset) \
-static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", \
- PWM_FROM_REG(data->pwm[offset-1], \
- FAN_CONFIG_INVERT(data->fan_conf, \
- offset-1))); \
-} \
-static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->pwm[offset-1] = PWM_TO_REG(val, \
- FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
- pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
- data->pwm[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
- show_pwm##offset, set_pwm##offset);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
+ show_pwm, set_pwm, offset-1);
show_and_set_pwm(1)
show_and_set_pwm(2)
show_and_set_pwm(3)
+static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+ data->in_vref));
+}
+static ssize_t show_in_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN,
+ data->in_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[attr->index] = IN_TO_REG(val,
+ data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX,
+ data->in_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_in(offset) \
-static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
- data->in_vref)); \
-} \
-static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", data->in_status[offset]); \
-} \
-static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
- data->in_min[offset]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_max[offset] = IN_TO_REG(val, \
- data->in_vref); \
- pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
- data->in_max[offset]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset##_input, NULL); \
-static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
- show_in##offset##_max, set_in##offset##_max); \
-static DEVICE_ATTR(in##offset##_status, S_IRUGO, \
- show_in##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+ show_in_max, set_in_max, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_status, S_IRUGO, \
+ show_in_status, NULL, offset);
show_and_set_in(0)
show_and_set_in(1)
show_and_set_in(2)
@@ -425,88 +430,97 @@ show_and_set_in(8)
show_and_set_in(9)
show_and_set_in(10)
+static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index],
+ data->in_vref));
+}
+static ssize_t show_therm_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11],
+ data->in_vref));
+}
+static ssize_t show_therm_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_status[attr->index]);
+}
+static ssize_t set_therm_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_min[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN,
+ data->in_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_max[attr->index] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX,
+ data->in_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref);
+ pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT,
+ data->in_crit[attr->index-11]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_therm(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \
- data->in_vref)); \
-} \
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%u\n", data->in_status[offset+7]); \
-} \
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
- data->in_min[offset+7]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
- data->in_max[offset+7]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
- pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
- data->in_crit[offset-4]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
- show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
- show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
- show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
- show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
- show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_therm_input, NULL, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+ show_therm_min, set_therm_min, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+ show_therm_max, set_therm_max, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+ show_therm_crit, set_therm_crit, 11+offset-4); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+ show_therm_status, NULL, 11+offset-4);
show_and_set_therm(4)
show_and_set_therm(5)
show_and_set_therm(6)
@@ -539,84 +553,93 @@ static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index]));
+}
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index]));
+}
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[attr->index]));
+}
+static ssize_t show_temp_status(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%d\n", data->temp_status[attr->index]);
+}
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_min[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN,
+ data->temp_min[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_max[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX,
+ data->temp_max[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ down(&data->update_lock);
+ data->temp_crit[attr->index] = TEMP_TO_REG(val);
+ pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT,
+ data->temp_crit[attr->index]);
+ up(&data->update_lock);
+ return count;
+}
+
#define show_and_set_temp(offset) \
-static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
-} \
-static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
-} \
-static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
-}\
-static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \
-}\
-static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct pc87360_data *data = pc87360_update_device(dev); \
- return sprintf(buf, "%d\n", data->temp_status[offset-1]); \
-}\
-static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_min[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
- data->temp_min[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_max[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
- data->temp_max[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct pc87360_data *data = i2c_get_clientdata(client); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- down(&data->update_lock); \
- data->temp_crit[offset-1] = TEMP_TO_REG(val); \
- pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
- data->temp_crit[offset-1]); \
- up(&data->update_lock); \
- return count; \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
- show_temp##offset##_input, NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
- show_temp##offset##_min, set_temp##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
- show_temp##offset##_max, set_temp##offset##_max); \
-static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
- show_temp##offset##_crit, set_temp##offset##_crit); \
-static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
- show_temp##offset##_status, NULL);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp_input, NULL, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+ show_temp_min, set_temp_min, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+ show_temp_max, set_temp_max, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+ show_temp_crit, set_temp_crit, offset-1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+ show_temp_status, NULL, offset-1);
show_and_set_temp(1)
show_and_set_temp(2)
show_and_set_temp(3)
@@ -632,12 +655,7 @@ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
* Device detection, registration and update
*/
-static int pc87360_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_detect(adapter, &addr_data, pc87360_detect);
-}
-
-static int pc87360_find(int sioaddr, u8 *devid, int *address)
+static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses)
{
u16 val;
int i;
@@ -683,7 +701,7 @@ static int pc87360_find(int sioaddr, u8 *devid, int *address)
continue;
}
- address[i] = val;
+ addresses[i] = val;
if (i==0) { /* Fans */
confreg[0] = superio_inb(sioaddr, 0xF0);
@@ -727,9 +745,7 @@ static int pc87360_find(int sioaddr, u8 *devid, int *address)
return 0;
}
-/* We don't really care about the address.
- Read from extra_isa instead. */
-int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
+static int pc87360_detect(struct i2c_adapter *adapter)
{
int i;
struct i2c_client *new_client;
@@ -738,9 +754,6 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
const char *name = "pc87360";
int use_thermistors = 0;
- if (!i2c_is_isa_adapter(adapter))
- return -ENODEV;
-
if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
return -ENOMEM;
memset(data, 0x00, sizeof(struct pc87360_data));
@@ -838,51 +851,57 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
if (data->innr) {
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in7_input);
- device_create_file(&new_client->dev, &dev_attr_in8_input);
- device_create_file(&new_client->dev, &dev_attr_in9_input);
- device_create_file(&new_client->dev, &dev_attr_in10_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in7_min);
- device_create_file(&new_client->dev, &dev_attr_in8_min);
- device_create_file(&new_client->dev, &dev_attr_in9_min);
- device_create_file(&new_client->dev, &dev_attr_in10_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_in7_max);
- device_create_file(&new_client->dev, &dev_attr_in8_max);
- device_create_file(&new_client->dev, &dev_attr_in9_max);
- device_create_file(&new_client->dev, &dev_attr_in10_max);
- device_create_file(&new_client->dev, &dev_attr_in0_status);
- device_create_file(&new_client->dev, &dev_attr_in1_status);
- device_create_file(&new_client->dev, &dev_attr_in2_status);
- device_create_file(&new_client->dev, &dev_attr_in3_status);
- device_create_file(&new_client->dev, &dev_attr_in4_status);
- device_create_file(&new_client->dev, &dev_attr_in5_status);
- device_create_file(&new_client->dev, &dev_attr_in6_status);
- device_create_file(&new_client->dev, &dev_attr_in7_status);
- device_create_file(&new_client->dev, &dev_attr_in8_status);
- device_create_file(&new_client->dev, &dev_attr_in9_status);
- device_create_file(&new_client->dev, &dev_attr_in10_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in0_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in1_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in2_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in3_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in4_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in5_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in6_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in7_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in8_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in9_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_in10_status.dev_attr);
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_vrm);
@@ -890,90 +909,92 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
}
if (data->tempnr) {
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_status);
- device_create_file(&new_client->dev, &dev_attr_temp2_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp1_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp2_status.dev_attr);
device_create_file(&new_client->dev, &dev_attr_alarms_temp);
}
if (data->tempnr == 3) {
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
- device_create_file(&new_client->dev, &dev_attr_temp3_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp3_status.dev_attr);
}
if (data->innr == 14) {
- device_create_file(&new_client->dev, &dev_attr_temp4_input);
- device_create_file(&new_client->dev, &dev_attr_temp5_input);
- device_create_file(&new_client->dev, &dev_attr_temp6_input);
- device_create_file(&new_client->dev, &dev_attr_temp4_min);
- device_create_file(&new_client->dev, &dev_attr_temp5_min);
- device_create_file(&new_client->dev, &dev_attr_temp6_min);
- device_create_file(&new_client->dev, &dev_attr_temp4_max);
- device_create_file(&new_client->dev, &dev_attr_temp5_max);
- device_create_file(&new_client->dev, &dev_attr_temp6_max);
- device_create_file(&new_client->dev, &dev_attr_temp4_crit);
- device_create_file(&new_client->dev, &dev_attr_temp5_crit);
- device_create_file(&new_client->dev, &dev_attr_temp6_crit);
- device_create_file(&new_client->dev, &dev_attr_temp4_status);
- device_create_file(&new_client->dev, &dev_attr_temp5_status);
- device_create_file(&new_client->dev, &dev_attr_temp6_status);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_input.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_min.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_max.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_crit.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp4_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp5_status.dev_attr);
+ device_create_file(&new_client->dev, &sensor_dev_attr_temp6_status.dev_attr);
}
if (data->fannr) {
if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) {
device_create_file(&new_client->dev,
- &dev_attr_fan1_input);
+ &sensor_dev_attr_fan1_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_min);
+ &sensor_dev_attr_fan1_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_div);
+ &sensor_dev_attr_fan1_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan1_status);
+ &sensor_dev_attr_fan1_status.dev_attr);
}
if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) {
device_create_file(&new_client->dev,
- &dev_attr_fan2_input);
+ &sensor_dev_attr_fan2_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_min);
+ &sensor_dev_attr_fan2_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_div);
+ &sensor_dev_attr_fan2_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan2_status);
+ &sensor_dev_attr_fan2_status.dev_attr);
}
if (FAN_CONFIG_CONTROL(data->fan_conf, 0))
- device_create_file(&new_client->dev, &dev_attr_pwm1);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
if (FAN_CONFIG_CONTROL(data->fan_conf, 1))
- device_create_file(&new_client->dev, &dev_attr_pwm2);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
}
if (data->fannr == 3) {
if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) {
device_create_file(&new_client->dev,
- &dev_attr_fan3_input);
+ &sensor_dev_attr_fan3_input.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_min);
+ &sensor_dev_attr_fan3_min.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_div);
+ &sensor_dev_attr_fan3_div.dev_attr);
device_create_file(&new_client->dev,
- &dev_attr_fan3_status);
+ &sensor_dev_attr_fan3_status.dev_attr);
}
if (FAN_CONFIG_CONTROL(data->fan_conf, 2))
- device_create_file(&new_client->dev, &dev_attr_pwm3);
+ device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
}
return 0;
+ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -990,11 +1011,10 @@ static int pc87360_detach_client(struct i2c_client *client)
struct pc87360_data *data = i2c_get_clientdata(client);
int i;
- if ((i = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((i = i2c_detach_client(client)))
return i;
- }
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -1320,23 +1340,23 @@ static int __init pc87360_init(void)
/* Arbitrarily pick one of the addresses */
for (i = 0; i < 3; i++) {
if (extra_isa[i] != 0x0000) {
- normal_isa[0] = extra_isa[i];
+ address = extra_isa[i];
break;
}
}
- if (normal_isa[0] == 0x0000) {
+ if (address == 0x0000) {
printk(KERN_WARNING "pc87360: No active logical device, "
"module not inserted.\n");
return -ENODEV;
}
- return i2c_add_driver(&pc87360_driver);
+ return i2c_isa_add_driver(&pc87360_driver);
}
static void __exit pc87360_exit(void)
{
- i2c_del_driver(&pc87360_driver);
+ i2c_isa_del_driver(&pc87360_driver);
}
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 6bbfc8fb4f13..21aa9a41f62c 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -55,7 +55,9 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <asm/io.h>
@@ -68,14 +70,10 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Addresses to scan.
+/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(sis5595);
+static unsigned short address;
/* Many SIS5595 constants specified below */
@@ -168,6 +166,7 @@ static inline u8 DIV_TO_REG(int val)
allocated. */
struct sis5595_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -190,8 +189,7 @@ struct sis5595_data {
static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
-static int sis5595_attach_adapter(struct i2c_adapter *adapter);
-static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind);
+static int sis5595_detect(struct i2c_adapter *adapter);
static int sis5595_detach_client(struct i2c_client *client);
static int sis5595_read_value(struct i2c_client *client, u8 register);
@@ -202,9 +200,7 @@ static void sis5595_init_client(struct i2c_client *client);
static struct i2c_driver sis5595_driver = {
.owner = THIS_MODULE,
.name = "sis5595",
- .id = I2C_DRIVERID_SIS5595,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = sis5595_attach_adapter,
+ .attach_adapter = sis5595_detect,
.detach_client = sis5595_detach_client,
};
@@ -476,14 +472,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/* This is called when the module is loaded */
-static int sis5595_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, sis5595_detect);
-}
-
-int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
+static int sis5595_detect(struct i2c_adapter *adapter)
{
int err = 0;
int i;
@@ -492,10 +481,6 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
char val;
u16 a;
- /* Make sure we are probing the ISA bus!! */
- if (!i2c_is_isa_adapter(adapter))
- goto exit;
-
if (force_addr)
address = force_addr & ~(SIS5595_EXTENT - 1);
/* Reserve the ISA region */
@@ -578,6 +563,12 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
@@ -608,7 +599,9 @@ int sis5595_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
}
return 0;
-
+
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit_release:
@@ -619,18 +612,17 @@ exit:
static int sis5595_detach_client(struct i2c_client *client)
{
+ struct sis5595_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- if (i2c_is_isa_client(client))
- release_region(client->addr, SIS5595_EXTENT);
+ release_region(client->addr, SIS5595_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -745,7 +737,6 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
{
u16 val;
int *i;
- int addr = 0;
for (i = blacklist; *i != 0; i++) {
struct pci_dev *dev;
@@ -761,22 +752,14 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
pci_read_config_word(dev, SIS5595_BASE_REG, &val))
return -ENODEV;
- addr = val & ~(SIS5595_EXTENT - 1);
- if (addr == 0 && force_addr == 0) {
+ address = val & ~(SIS5595_EXTENT - 1);
+ if (address == 0 && force_addr == 0) {
dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
- if (force_addr)
- addr = force_addr; /* so detect will get called */
-
- if (!addr) {
- dev_err(&dev->dev,"No SiS 5595 sensors found.\n");
- return -ENODEV;
- }
- normal_isa[0] = addr;
s_bridge = pci_dev_get(dev);
- if (i2c_add_driver(&sis5595_driver)) {
+ if (i2c_isa_add_driver(&sis5595_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
}
@@ -803,7 +786,7 @@ static void __exit sm_sis5595_exit(void)
{
pci_unregister_driver(&sis5595_pci_driver);
if (s_bridge != NULL) {
- i2c_del_driver(&sis5595_driver);
+ i2c_isa_del_driver(&sis5595_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index fdeeb3ab6f2f..7fe71576dea4 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -31,23 +31,14 @@
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47b397 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .probe = normal_i2c, /* cheat */
- .ignore = normal_i2c, /* cheat */
- .forces = forces,
-};
+static unsigned short address;
/* Super-I/0 registers and commands */
@@ -100,6 +91,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
struct smsc47b397_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -215,52 +207,40 @@ sysfs_fan(4);
#define device_create_file_fan(client, num) \
device_create_file(&client->dev, &dev_attr_fan##num##_input)
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind);
-
-static int smsc47b397_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, smsc47b397_detect);
-}
-
static int smsc47b397_detach_client(struct i2c_client *client)
{
+ struct smsc47b397_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, SMSC_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
+static int smsc47b397_detect(struct i2c_adapter *adapter);
+
static struct i2c_driver smsc47b397_driver = {
.owner = THIS_MODULE,
.name = "smsc47b397",
- .id = I2C_DRIVERID_SMSC47B397,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = smsc47b397_attach_adapter,
+ .attach_adapter = smsc47b397_detect,
.detach_client = smsc47b397_detach_client,
};
-static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
+static int smsc47b397_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct smsc47b397_data *data;
int err = 0;
- if (!i2c_is_isa_adapter(adapter)) {
- return 0;
- }
-
- if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) {
- dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr);
+ if (!request_region(address, SMSC_EXTENT, smsc47b397_driver.name)) {
+ dev_err(&adapter->dev, "Region 0x%x already in use!\n",
+ address);
return -EBUSY;
}
@@ -272,7 +252,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
new_client = &data->client;
i2c_set_clientdata(new_client, data);
- new_client->addr = addr;
+ new_client->addr = address;
init_MUTEX(&data->lock);
new_client->adapter = adapter;
new_client->driver = &smsc47b397_driver;
@@ -285,6 +265,12 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
if ((err = i2c_attach_client(new_client)))
goto error_free;
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
device_create_file_temp(new_client, 1);
device_create_file_temp(new_client, 2);
device_create_file_temp(new_client, 3);
@@ -297,14 +283,16 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind)
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
error_release:
- release_region(addr, SMSC_EXTENT);
+ release_region(address, SMSC_EXTENT);
return err;
}
-static int __init smsc47b397_find(unsigned int *addr)
+static int __init smsc47b397_find(unsigned short *addr)
{
u8 id, rev;
@@ -333,15 +321,15 @@ static int __init smsc47b397_init(void)
{
int ret;
- if ((ret = smsc47b397_find(normal_isa)))
+ if ((ret = smsc47b397_find(&address)))
return ret;
- return i2c_add_driver(&smsc47b397_driver);
+ return i2c_isa_add_driver(&smsc47b397_driver);
}
static void __exit smsc47b397_exit(void)
{
- i2c_del_driver(&smsc47b397_driver);
+ i2c_isa_del_driver(&smsc47b397_driver);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 7166ad0b2fda..c9cc683eba4a 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -2,8 +2,8 @@
smsc47m1.c - Part of lm_sensors, Linux kernel modules
for hardware monitoring
- Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x
- Super-I/O chips.
+ Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,
+ LPC47M15x and LPC47M192 Super-I/O chips.
Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
@@ -30,21 +30,14 @@
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Address is autodetected, there is no default value */
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-static struct i2c_force_data forces[] = {{NULL}};
-
-enum chips { any_chip, smsc47m1 };
-static struct i2c_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .normal_isa = normal_isa,
- .forces = forces,
-};
+static unsigned short address;
/* Super-I/0 registers and commands */
@@ -108,6 +101,7 @@ superio_exit(void)
struct smsc47m1_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -121,9 +115,7 @@ struct smsc47m1_data {
};
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
-static int smsc47m1_find(int *address);
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind);
+static int smsc47m1_detect(struct i2c_adapter *adapter);
static int smsc47m1_detach_client(struct i2c_client *client);
static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
@@ -136,9 +128,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
static struct i2c_driver smsc47m1_driver = {
.owner = THIS_MODULE,
.name = "smsc47m1",
- .id = I2C_DRIVERID_SMSC47M1,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = smsc47m1_attach_adapter,
+ .attach_adapter = smsc47m1_detect,
.detach_client = smsc47m1_detach_client,
};
@@ -354,14 +344,7 @@ fan_present(2);
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
-static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, smsc47m1_detect);
-}
-
-static int smsc47m1_find(int *address)
+static int __init smsc47m1_find(unsigned short *addr)
{
u8 val;
@@ -388,10 +371,10 @@ static int smsc47m1_find(int *address)
}
superio_select();
- *address = (superio_inb(SUPERIO_REG_BASE) << 8)
- | superio_inb(SUPERIO_REG_BASE + 1);
+ *addr = (superio_inb(SUPERIO_REG_BASE) << 8)
+ | superio_inb(SUPERIO_REG_BASE + 1);
val = superio_inb(SUPERIO_REG_ACT);
- if (*address == 0 || (val & 0x01) == 0) {
+ if (*addr == 0 || (val & 0x01) == 0) {
printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
superio_exit();
return -ENODEV;
@@ -401,17 +384,13 @@ static int smsc47m1_find(int *address)
return 0;
}
-static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
+static int smsc47m1_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct smsc47m1_data *data;
int err = 0;
int fan1, fan2, pwm1, pwm2;
- if (!i2c_is_isa_adapter(adapter)) {
- return 0;
- }
-
if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {
dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
return -EBUSY;
@@ -461,6 +440,13 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
function. */
smsc47m1_update_device(&new_client->dev, 1);
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_detach;
+ }
+
if (fan1) {
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
@@ -494,6 +480,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+error_detach:
+ i2c_detach_client(new_client);
error_free:
kfree(data);
error_release:
@@ -503,16 +491,16 @@ error_release:
static int smsc47m1_detach_client(struct i2c_client *client)
{
+ struct smsc47m1_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, SMSC_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -573,16 +561,16 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
static int __init sm_smsc47m1_init(void)
{
- if (smsc47m1_find(normal_isa)) {
+ if (smsc47m1_find(&address)) {
return -ENODEV;
}
- return i2c_add_driver(&smsc47m1_driver);
+ return i2c_isa_add_driver(&smsc47m1_driver);
}
static void __exit sm_smsc47m1_exit(void)
{
- i2c_del_driver(&smsc47m1_driver);
+ i2c_isa_del_driver(&smsc47m1_driver);
}
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 164d47948390..05ddc88e7dd2 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -35,7 +35,9 @@
#include <linux/pci.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -47,14 +49,10 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Addresses to scan.
+/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(via686a);
+static unsigned short address;
/*
The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -297,6 +295,7 @@ static inline long TEMP_FROM_REG10(u16 val)
via686a client is allocated. */
struct via686a_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -315,8 +314,7 @@ struct via686a_data {
static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
-static int via686a_attach_adapter(struct i2c_adapter *adapter);
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind);
+static int via686a_detect(struct i2c_adapter *adapter);
static int via686a_detach_client(struct i2c_client *client);
static inline int via686a_read_value(struct i2c_client *client, u8 reg)
@@ -576,22 +574,13 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static struct i2c_driver via686a_driver = {
.owner = THIS_MODULE,
.name = "via686a",
- .id = I2C_DRIVERID_VIA686A,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = via686a_attach_adapter,
+ .attach_adapter = via686a_detect,
.detach_client = via686a_detach_client,
};
/* This is called when the module is loaded */
-static int via686a_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, via686a_detect);
-}
-
-static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
+static int via686a_detect(struct i2c_adapter *adapter)
{
struct i2c_client *new_client;
struct via686a_data *data;
@@ -599,13 +588,6 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
const char client_name[] = "via686a";
u16 val;
- /* Make sure we are probing the ISA bus!! */
- if (!i2c_is_isa_adapter(adapter)) {
- dev_err(&adapter->dev,
- "via686a_detect called for an I2C bus adapter?!?\n");
- return 0;
- }
-
/* 8231 requires multiple of 256, we enforce that on 686 as well */
if (force_addr)
address = force_addr & 0xFF00;
@@ -637,7 +619,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) {
err = -ENOMEM;
- goto ERROR0;
+ goto exit_release;
}
memset(data, 0, sizeof(struct via686a_data));
@@ -655,12 +637,18 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
init_MUTEX(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
- goto ERROR3;
+ goto exit_free;
/* Initialize the VIA686A chip */
via686a_init_client(new_client);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
@@ -695,25 +683,27 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
-ERROR3:
+exit_detach:
+ i2c_detach_client(new_client);
+exit_free:
kfree(data);
-ERROR0:
+exit_release:
release_region(address, VIA686A_EXTENT);
return err;
}
static int via686a_detach_client(struct i2c_client *client)
{
+ struct via686a_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, VIA686A_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -810,29 +800,20 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 val;
- int addr = 0;
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
return -ENODEV;
- addr = val & ~(VIA686A_EXTENT - 1);
- if (addr == 0 && force_addr == 0) {
+ address = val & ~(VIA686A_EXTENT - 1);
+ if (address == 0 && force_addr == 0) {
dev_err(&dev->dev, "base address not set - upgrade BIOS "
"or use force_addr=0xaddr\n");
return -ENODEV;
}
- if (force_addr)
- addr = force_addr; /* so detect will get called */
-
- if (!addr) {
- dev_err(&dev->dev, "No Via 686A sensors found.\n");
- return -ENODEV;
- }
- normal_isa[0] = addr;
s_bridge = pci_dev_get(dev);
- if (i2c_add_driver(&via686a_driver)) {
+ if (i2c_isa_add_driver(&via686a_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
}
@@ -859,7 +840,7 @@ static void __exit sm_via686a_exit(void)
{
pci_unregister_driver(&via686a_pci_driver);
if (s_bridge != NULL) {
- i2c_del_driver(&via686a_driver);
+ i2c_isa_del_driver(&via686a_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 8a40b6976e1a..b60efe8f8b26 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -9,6 +9,9 @@
Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
in testing and debugging this driver.
+ This driver also supports the W83627EHG, which is the lead-free
+ version of the W83627EHF.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -37,17 +40,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
-/* Addresses to scan
- The actual ISA address is read from Super-I/O configuration space */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
-
-/* Insmod parameters */
-SENSORS_INSMOD_1(w83627ehf);
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
/*
* Super-I/O constants and functions
@@ -174,6 +174,7 @@ temp1_to_reg(int temp)
struct w83627ehf_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
struct semaphore update_lock;
@@ -666,15 +667,12 @@ static void w83627ehf_init_client(struct i2c_client *client)
}
}
-static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
+static int w83627ehf_detect(struct i2c_adapter *adapter)
{
struct i2c_client *client;
struct w83627ehf_data *data;
int i, err = 0;
- if (!i2c_is_isa_adapter(adapter))
- return 0;
-
if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
err = -EBUSY;
goto exit;
@@ -720,6 +718,12 @@ static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
data->has_fan |= (1 << 4);
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&client->dev, &dev_attr_fan1_input);
device_create_file(&client->dev, &dev_attr_fan1_min);
device_create_file(&client->dev, &dev_attr_fan1_div);
@@ -753,6 +757,8 @@ static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+exit_detach:
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit_release:
@@ -761,24 +767,17 @@ exit:
return err;
}
-static int w83627ehf_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_detect(adapter, &addr_data, w83627ehf_detect);
-}
-
static int w83627ehf_detach_client(struct i2c_client *client)
{
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, REGION_LENGTH);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -786,12 +785,11 @@ static int w83627ehf_detach_client(struct i2c_client *client)
static struct i2c_driver w83627ehf_driver = {
.owner = THIS_MODULE,
.name = "w83627ehf",
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = w83627ehf_attach_adapter,
+ .attach_adapter = w83627ehf_detect,
.detach_client = w83627ehf_detach_client,
};
-static int __init w83627ehf_find(int sioaddr, int *address)
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -809,8 +807,8 @@ static int __init w83627ehf_find(int sioaddr, int *address)
superio_select(W83627EHF_LD_HWM);
val = (superio_inb(SIO_REG_ADDR) << 8)
| superio_inb(SIO_REG_ADDR + 1);
- *address = val & ~(REGION_LENGTH - 1);
- if (*address == 0) {
+ *addr = val & ~(REGION_LENGTH - 1);
+ if (*addr == 0) {
superio_exit();
return -ENODEV;
}
@@ -826,16 +824,16 @@ static int __init w83627ehf_find(int sioaddr, int *address)
static int __init sensors_w83627ehf_init(void)
{
- if (w83627ehf_find(0x2e, &normal_isa[0])
- && w83627ehf_find(0x4e, &normal_isa[0]))
+ if (w83627ehf_find(0x2e, &address)
+ && w83627ehf_find(0x4e, &address))
return -ENODEV;
- return i2c_add_driver(&w83627ehf_driver);
+ return i2c_isa_add_driver(&w83627ehf_driver);
}
static void __exit sensors_w83627ehf_exit(void)
{
- i2c_del_driver(&w83627ehf_driver);
+ i2c_isa_del_driver(&w83627ehf_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index bd87a42e068a..3479dc5208e2 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -42,8 +42,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
@@ -56,12 +58,15 @@ module_param(force_i2c, byte, 0);
MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors");
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+/* The actual ISA address is read from Super-I/O configuration space */
+static unsigned short address;
/* Insmod parameters */
-SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);
+enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };
+
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
static int init = 1;
module_param(init, bool, 0);
@@ -277,6 +282,7 @@ static inline u8 DIV_TO_REG(long val)
dynamically allocated, at the same time when a new client is allocated. */
struct w83627hf_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -314,9 +320,7 @@ struct w83627hf_data {
};
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter);
-static int w83627hf_detect(struct i2c_adapter *adapter, int address,
- int kind);
+static int w83627hf_detect(struct i2c_adapter *adapter);
static int w83627hf_detach_client(struct i2c_client *client);
static int w83627hf_read_value(struct i2c_client *client, u16 register);
@@ -328,9 +332,7 @@ static void w83627hf_init_client(struct i2c_client *client);
static struct i2c_driver w83627hf_driver = {
.owner = THIS_MODULE,
.name = "w83627hf",
- .id = I2C_DRIVERID_W83627HF,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = w83627hf_attach_adapter,
+ .attach_adapter = w83627hf_detect,
.detach_client = w83627hf_detach_client,
};
@@ -959,16 +961,7 @@ device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
} while (0)
-/* This function is called when:
- * w83627hf_driver is inserted (when this module is loaded), for each
- available adapter
- * when a new adapter is inserted (and w83627hf_driver is still present) */
-static int w83627hf_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_detect(adapter, &addr_data, w83627hf_detect);
-}
-
-static int w83627hf_find(int sioaddr, int *address)
+static int __init w83627hf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -988,32 +981,24 @@ static int w83627hf_find(int sioaddr, int *address)
superio_select(W83627HF_LD_HWM);
val = (superio_inb(WINB_BASE_REG) << 8) |
superio_inb(WINB_BASE_REG + 1);
- *address = val & ~(WINB_EXTENT - 1);
- if (*address == 0 && force_addr == 0) {
+ *addr = val & ~(WINB_EXTENT - 1);
+ if (*addr == 0 && force_addr == 0) {
superio_exit();
return -ENODEV;
}
- if (force_addr)
- *address = force_addr; /* so detect will get called */
superio_exit();
return 0;
}
-int w83627hf_detect(struct i2c_adapter *adapter, int address,
- int kind)
+static int w83627hf_detect(struct i2c_adapter *adapter)
{
- int val;
+ int val, kind;
struct i2c_client *new_client;
struct w83627hf_data *data;
int err = 0;
const char *client_name = "";
- if (!i2c_is_isa_adapter(adapter)) {
- err = -ENODEV;
- goto ERROR0;
- }
-
if(force_addr)
address = force_addr & ~(WINB_EXTENT - 1);
@@ -1102,6 +1087,12 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+
device_create_file_in(new_client, 0);
if (kind != w83697hf)
device_create_file_in(new_client, 1);
@@ -1152,6 +1143,8 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
return 0;
+ ERROR3:
+ i2c_detach_client(new_client);
ERROR2:
kfree(data);
ERROR1:
@@ -1162,16 +1155,16 @@ int w83627hf_detect(struct i2c_adapter *adapter, int address,
static int w83627hf_detach_client(struct i2c_client *client)
{
+ struct w83627hf_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
release_region(client->addr, WINB_EXTENT);
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
@@ -1290,7 +1283,15 @@ static void w83627hf_init_client(struct i2c_client *client)
int type = data->type;
u8 tmp;
- if(init) {
+ if (reset) {
+ /* Resetting the chip has been the default for a long time,
+ but repeatedly caused problems (fans going to full
+ speed...) so it is now optional. It might even go away if
+ nobody reports it as being useful, as I see very little
+ reason why this would be needed at all. */
+ dev_info(&client->dev, "If reset=1 solved a problem you were "
+ "having, please report!\n");
+
/* save this register */
i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
/* Reset all except Watchdog values and last conversion values
@@ -1327,7 +1328,7 @@ static void w83627hf_init_client(struct i2c_client *client)
data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;
} else {
/* Convert VID to voltage based on default VRM */
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
}
tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
@@ -1485,20 +1486,17 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
static int __init sensors_w83627hf_init(void)
{
- int addr;
-
- if (w83627hf_find(0x2e, &addr)
- && w83627hf_find(0x4e, &addr)) {
+ if (w83627hf_find(0x2e, &address)
+ && w83627hf_find(0x4e, &address)) {
return -ENODEV;
}
- normal_isa[0] = addr;
- return i2c_add_driver(&w83627hf_driver);
+ return i2c_isa_add_driver(&w83627hf_driver);
}
static void __exit sensors_w83627hf_exit(void)
{
- i2c_del_driver(&w83627hf_driver);
+ i2c_isa_del_driver(&w83627hf_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 0bb131ce09eb..4c43337ca780 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -38,8 +38,10 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/i2c-isa.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
#include <asm/io.h>
#include "lm75.h"
@@ -47,10 +49,10 @@
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
+static unsigned short isa_address = 0x290;
/* Insmod parameters */
-SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
+I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
@@ -218,6 +220,7 @@ DIV_TO_REG(long val, enum chips type)
allocated. */
struct w83781d_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore lock;
enum chips type;
@@ -255,6 +258,7 @@ struct w83781d_data {
};
static int w83781d_attach_adapter(struct i2c_adapter *adapter);
+static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
static int w83781d_detach_client(struct i2c_client *client);
@@ -273,6 +277,14 @@ static struct i2c_driver w83781d_driver = {
.detach_client = w83781d_detach_client,
};
+static struct i2c_driver w83781d_isa_driver = {
+ .owner = THIS_MODULE,
+ .name = "w83781d-isa",
+ .attach_adapter = w83781d_isa_attach_adapter,
+ .detach_client = w83781d_detach_client,
+};
+
+
/* following are the sysfs callback functions */
#define show_in_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
@@ -856,7 +868,13 @@ w83781d_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, w83781d_detect);
+ return i2c_probe(adapter, &addr_data, w83781d_detect);
+}
+
+static int
+w83781d_isa_attach_adapter(struct i2c_adapter *adapter)
+{
+ return w83781d_detect(adapter, isa_address, -1);
}
/* Assumes that adapter is of I2C, not ISA variety.
@@ -961,10 +979,10 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
ERROR_SC_3:
i2c_detach_client(data->lm75[0]);
ERROR_SC_2:
- if (NULL != data->lm75[1])
+ if (data->lm75[1])
kfree(data->lm75[1]);
ERROR_SC_1:
- if (NULL != data->lm75[0])
+ if (data->lm75[0])
kfree(data->lm75[0]);
ERROR_SC_0:
return err;
@@ -999,7 +1017,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if (is_isa)
if (!request_region(address, W83781D_EXTENT,
- w83781d_driver.name)) {
+ w83781d_isa_driver.name)) {
dev_dbg(&adapter->dev, "Request of region "
"0x%x-0x%x for w83781d failed\n", address,
address + W83781D_EXTENT - 1);
@@ -1057,7 +1075,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
new_client->addr = address;
init_MUTEX(&data->lock);
new_client->adapter = adapter;
- new_client->driver = &w83781d_driver;
+ new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
@@ -1189,6 +1207,12 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
data->pwmenable[i] = 1;
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
+ }
+
device_create_file_in(new_client, 0);
if (kind != w83783s)
device_create_file_in(new_client, 1);
@@ -1241,6 +1265,15 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
return 0;
+ERROR4:
+ if (data->lm75[1]) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+ if (data->lm75[0]) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -1255,24 +1288,26 @@ ERROR0:
static int
w83781d_detach_client(struct i2c_client *client)
{
+ struct w83781d_data *data = i2c_get_clientdata(client);
int err;
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
if (i2c_is_isa_client(client))
release_region(client->addr, W83781D_EXTENT);
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev,
- "Client deregistration failed, client not detached.\n");
+ if ((err = i2c_detach_client(client)))
return err;
- }
- if (i2c_get_clientdata(client)==NULL) {
- /* subclients */
+ /* main client */
+ if (data)
+ kfree(data);
+
+ /* subclient */
+ else
kfree(client);
- } else {
- /* main client */
- kfree(i2c_get_clientdata(client));
- }
return 0;
}
@@ -1443,7 +1478,7 @@ w83781d_init_client(struct i2c_client *client)
w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
}
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if ((type != w83781d) && (type != as99127f)) {
tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
@@ -1613,12 +1648,25 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
static int __init
sensors_w83781d_init(void)
{
- return i2c_add_driver(&w83781d_driver);
+ int res;
+
+ res = i2c_add_driver(&w83781d_driver);
+ if (res)
+ return res;
+
+ res = i2c_isa_add_driver(&w83781d_isa_driver);
+ if (res) {
+ i2c_del_driver(&w83781d_driver);
+ return res;
+ }
+
+ return 0;
}
static void __exit
sensors_w83781d_exit(void)
{
+ i2c_isa_del_driver(&w83781d_isa_driver);
i2c_del_driver(&w83781d_driver);
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
new file mode 100644
index 000000000000..ba0c28015f6a
--- /dev/null
+++ b/drivers/hwmon/w83792d.c
@@ -0,0 +1,1649 @@
+/*
+ w83792d.c - Part of lm_sensors, Linux kernel modules for hardware
+ monitoring
+ Copyright (C) 2004, 2005 Winbond Electronics Corp.
+ Chunhao Huang <DZShen@Winbond.com.tw>,
+ Rudolf Marek <r.marek@sh.cvut.cz>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Note:
+ 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver.
+ 2. This driver is only for Winbond W83792D C version device, there
+ are also some motherboards with B version W83792D device. The
+ calculation method to in6-in7(measured value, limits) is a little
+ different between C and B version. C or B version can be identified
+ by CR[0x49h].
+*/
+
+/*
+ Supports following chips:
+
+ Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
+ w83792d 9 7 7 3 0x7a 0x5ca3 yes no
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(w83792d);
+I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+ "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to one to force chip initialization");
+
+/* The W83792D registers */
+static const u8 W83792D_REG_IN[9] = {
+ 0x20, /* Vcore A in DataSheet */
+ 0x21, /* Vcore B in DataSheet */
+ 0x22, /* VIN0 in DataSheet */
+ 0x23, /* VIN1 in DataSheet */
+ 0x24, /* VIN2 in DataSheet */
+ 0x25, /* VIN3 in DataSheet */
+ 0x26, /* 5VCC in DataSheet */
+ 0xB0, /* 5VSB in DataSheet */
+ 0xB1 /* VBAT in DataSheet */
+};
+#define W83792D_REG_LOW_BITS1 0x3E /* Low Bits I in DataSheet */
+#define W83792D_REG_LOW_BITS2 0x3F /* Low Bits II in DataSheet */
+static const u8 W83792D_REG_IN_MAX[9] = {
+ 0x2B, /* Vcore A High Limit in DataSheet */
+ 0x2D, /* Vcore B High Limit in DataSheet */
+ 0x2F, /* VIN0 High Limit in DataSheet */
+ 0x31, /* VIN1 High Limit in DataSheet */
+ 0x33, /* VIN2 High Limit in DataSheet */
+ 0x35, /* VIN3 High Limit in DataSheet */
+ 0x37, /* 5VCC High Limit in DataSheet */
+ 0xB4, /* 5VSB High Limit in DataSheet */
+ 0xB6 /* VBAT High Limit in DataSheet */
+};
+static const u8 W83792D_REG_IN_MIN[9] = {
+ 0x2C, /* Vcore A Low Limit in DataSheet */
+ 0x2E, /* Vcore B Low Limit in DataSheet */
+ 0x30, /* VIN0 Low Limit in DataSheet */
+ 0x32, /* VIN1 Low Limit in DataSheet */
+ 0x34, /* VIN2 Low Limit in DataSheet */
+ 0x36, /* VIN3 Low Limit in DataSheet */
+ 0x38, /* 5VCC Low Limit in DataSheet */
+ 0xB5, /* 5VSB Low Limit in DataSheet */
+ 0xB7 /* VBAT Low Limit in DataSheet */
+};
+static const u8 W83792D_REG_FAN[7] = {
+ 0x28, /* FAN 1 Count in DataSheet */
+ 0x29, /* FAN 2 Count in DataSheet */
+ 0x2A, /* FAN 3 Count in DataSheet */
+ 0xB8, /* FAN 4 Count in DataSheet */
+ 0xB9, /* FAN 5 Count in DataSheet */
+ 0xBA, /* FAN 6 Count in DataSheet */
+ 0xBE /* FAN 7 Count in DataSheet */
+};
+static const u8 W83792D_REG_FAN_MIN[7] = {
+ 0x3B, /* FAN 1 Count Low Limit in DataSheet */
+ 0x3C, /* FAN 2 Count Low Limit in DataSheet */
+ 0x3D, /* FAN 3 Count Low Limit in DataSheet */
+ 0xBB, /* FAN 4 Count Low Limit in DataSheet */
+ 0xBC, /* FAN 5 Count Low Limit in DataSheet */
+ 0xBD, /* FAN 6 Count Low Limit in DataSheet */
+ 0xBF /* FAN 7 Count Low Limit in DataSheet */
+};
+#define W83792D_REG_FAN_CFG 0x84 /* FAN Configuration in DataSheet */
+static const u8 W83792D_REG_FAN_DIV[4] = {
+ 0x47, /* contains FAN2 and FAN1 Divisor */
+ 0x5B, /* contains FAN4 and FAN3 Divisor */
+ 0x5C, /* contains FAN6 and FAN5 Divisor */
+ 0x9E /* contains FAN7 Divisor. */
+};
+static const u8 W83792D_REG_PWM[7] = {
+ 0x81, /* FAN 1 Duty Cycle, be used to control */
+ 0x83, /* FAN 2 Duty Cycle, be used to control */
+ 0x94, /* FAN 3 Duty Cycle, be used to control */
+ 0xA3, /* FAN 4 Duty Cycle, be used to control */
+ 0xA4, /* FAN 5 Duty Cycle, be used to control */
+ 0xA5, /* FAN 6 Duty Cycle, be used to control */
+ 0xA6 /* FAN 7 Duty Cycle, be used to control */
+};
+#define W83792D_REG_BANK 0x4E
+#define W83792D_REG_TEMP2_CONFIG 0xC2
+#define W83792D_REG_TEMP3_CONFIG 0xCA
+
+static const u8 W83792D_REG_TEMP1[3] = {
+ 0x27, /* TEMP 1 in DataSheet */
+ 0x39, /* TEMP 1 Over in DataSheet */
+ 0x3A, /* TEMP 1 Hyst in DataSheet */
+};
+
+static const u8 W83792D_REG_TEMP_ADD[2][6] = {
+ { 0xC0, /* TEMP 2 in DataSheet */
+ 0xC1, /* TEMP 2(0.5 deg) in DataSheet */
+ 0xC5, /* TEMP 2 Over High part in DataSheet */
+ 0xC6, /* TEMP 2 Over Low part in DataSheet */
+ 0xC3, /* TEMP 2 Thyst High part in DataSheet */
+ 0xC4 }, /* TEMP 2 Thyst Low part in DataSheet */
+ { 0xC8, /* TEMP 3 in DataSheet */
+ 0xC9, /* TEMP 3(0.5 deg) in DataSheet */
+ 0xCD, /* TEMP 3 Over High part in DataSheet */
+ 0xCE, /* TEMP 3 Over Low part in DataSheet */
+ 0xCB, /* TEMP 3 Thyst High part in DataSheet */
+ 0xCC } /* TEMP 3 Thyst Low part in DataSheet */
+};
+
+static const u8 W83792D_REG_THERMAL[3] = {
+ 0x85, /* SmartFanI: Fan1 target value */
+ 0x86, /* SmartFanI: Fan2 target value */
+ 0x96 /* SmartFanI: Fan3 target value */
+};
+
+static const u8 W83792D_REG_TOLERANCE[3] = {
+ 0x87, /* (bit3-0)SmartFan Fan1 tolerance */
+ 0x87, /* (bit7-4)SmartFan Fan2 tolerance */
+ 0x97 /* (bit3-0)SmartFan Fan3 tolerance */
+};
+
+static const u8 W83792D_REG_POINTS[3][4] = {
+ { 0x85, /* SmartFanII: Fan1 temp point 1 */
+ 0xE3, /* SmartFanII: Fan1 temp point 2 */
+ 0xE4, /* SmartFanII: Fan1 temp point 3 */
+ 0xE5 }, /* SmartFanII: Fan1 temp point 4 */
+ { 0x86, /* SmartFanII: Fan2 temp point 1 */
+ 0xE6, /* SmartFanII: Fan2 temp point 2 */
+ 0xE7, /* SmartFanII: Fan2 temp point 3 */
+ 0xE8 }, /* SmartFanII: Fan2 temp point 4 */
+ { 0x96, /* SmartFanII: Fan3 temp point 1 */
+ 0xE9, /* SmartFanII: Fan3 temp point 2 */
+ 0xEA, /* SmartFanII: Fan3 temp point 3 */
+ 0xEB } /* SmartFanII: Fan3 temp point 4 */
+};
+
+static const u8 W83792D_REG_LEVELS[3][4] = {
+ { 0x88, /* (bit3-0) SmartFanII: Fan1 Non-Stop */
+ 0x88, /* (bit7-4) SmartFanII: Fan1 Level 1 */
+ 0xE0, /* (bit7-4) SmartFanII: Fan1 Level 2 */
+ 0xE0 }, /* (bit3-0) SmartFanII: Fan1 Level 3 */
+ { 0x89, /* (bit3-0) SmartFanII: Fan2 Non-Stop */
+ 0x89, /* (bit7-4) SmartFanII: Fan2 Level 1 */
+ 0xE1, /* (bit7-4) SmartFanII: Fan2 Level 2 */
+ 0xE1 }, /* (bit3-0) SmartFanII: Fan2 Level 3 */
+ { 0x98, /* (bit3-0) SmartFanII: Fan3 Non-Stop */
+ 0x98, /* (bit7-4) SmartFanII: Fan3 Level 1 */
+ 0xE2, /* (bit7-4) SmartFanII: Fan3 Level 2 */
+ 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */
+};
+
+#define W83792D_REG_CONFIG 0x40
+#define W83792D_REG_VID_FANDIV 0x47
+#define W83792D_REG_CHIPID 0x49
+#define W83792D_REG_WCHIPID 0x58
+#define W83792D_REG_CHIPMAN 0x4F
+#define W83792D_REG_PIN 0x4B
+#define W83792D_REG_I2C_SUBADDR 0x4A
+
+#define W83792D_REG_ALARM1 0xA9 /* realtime status register1 */
+#define W83792D_REG_ALARM2 0xAA /* realtime status register2 */
+#define W83792D_REG_ALARM3 0xAB /* realtime status register3 */
+#define W83792D_REG_CHASSIS 0x42 /* Bit 5: Case Open status bit */
+#define W83792D_REG_CHASSIS_CLR 0x44 /* Bit 7: Case Open CLR_CHS/Reset bit */
+
+/* control in0/in1 's limit modifiability */
+#define W83792D_REG_VID_IN_B 0x17
+
+#define W83792D_REG_VBAT 0x5D
+#define W83792D_REG_I2C_ADDR 0x48
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG
+ variants. Note that you should be a bit careful with which arguments
+ these macros are called: arguments may be evaluated more than once.
+ Fixing this is just not worth it. */
+#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \
+ ((((nr)==6)||((nr)==7))?(val*6):(val*4)))
+#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \
+ ((((nr)==6)||((nr)==7))?(val/6):(val/4)))
+
+static inline u8
+FAN_TO_REG(long rpm, int div)
+{
+ if (rpm == 0)
+ return 255;
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
+}
+
+#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
+ ((val) == 255 ? 0 : \
+ 1350000 / ((val) * (div))))
+
+/* for temp1 */
+#define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+ : (val)) / 1000, 0, 0xff))
+#define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+/* for temp2 and temp3, because they need addtional resolution */
+#define TEMP_ADD_FROM_REG(val1, val2) \
+ ((((val1) & 0x80 ? (val1)-0x100 \
+ : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0))
+#define TEMP_ADD_TO_REG_HIGH(val) \
+ (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
+ : (val)) / 1000, 0, 0xff))
+#define TEMP_ADD_TO_REG_LOW(val) ((val%1000) ? 0x80 : 0x00)
+
+#define PWM_FROM_REG(val) (val)
+#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define DIV_FROM_REG(val) (1 << (val))
+
+static inline u8
+DIV_TO_REG(long val)
+{
+ int i;
+ val = SENSORS_LIMIT(val, 1, 128) >> 1;
+ for (i = 0; i < 6; i++) {
+ if (val == 0)
+ break;
+ val >>= 1;
+ }
+ return ((u8) i);
+}
+
+struct w83792d_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct semaphore lock;
+ enum chips type;
+
+ struct semaphore update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* array of 2 pointers to subclients */
+ struct i2c_client *lm75[2];
+
+ u8 in[9]; /* Register value */
+ u8 in_max[9]; /* Register value */
+ u8 in_min[9]; /* Register value */
+ u8 low_bits[2]; /* Additional resolution to voltage in0-6 */
+ u8 fan[7]; /* Register value */
+ u8 fan_min[7]; /* Register value */
+ u8 temp1[3]; /* current, over, thyst */
+ u8 temp_add[2][6]; /* Register value */
+ u8 fan_div[7]; /* Register encoding, shifted right */
+ u8 pwm[7]; /* We only consider the first 3 set of pwm,
+ although 792 chip has 7 set of pwm. */
+ u8 pwmenable[3];
+ u8 pwm_mode[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */
+ u32 alarms; /* realtime status register encoding,combined */
+ u8 chassis; /* Chassis status */
+ u8 chassis_clear; /* CLR_CHS, clear chassis intrusion detection */
+ u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */
+ u8 tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */
+ u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */
+ u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
+};
+
+static int w83792d_attach_adapter(struct i2c_adapter *adapter);
+static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
+static int w83792d_detach_client(struct i2c_client *client);
+
+static int w83792d_read_value(struct i2c_client *client, u8 register);
+static int w83792d_write_value(struct i2c_client *client, u8 register,
+ u8 value);
+static struct w83792d_data *w83792d_update_device(struct device *dev);
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
+#endif
+
+static void w83792d_init_client(struct i2c_client *client);
+
+static struct i2c_driver w83792d_driver = {
+ .owner = THIS_MODULE,
+ .name = "w83792d",
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = w83792d_attach_adapter,
+ .detach_client = w83792d_detach_client,
+};
+
+static long in_count_from_reg(int nr, struct w83792d_data *data)
+{
+ u16 vol_count = data->in[nr];
+ u16 low_bits = 0;
+ vol_count = (vol_count << 2);
+ switch (nr)
+ {
+ case 0: /* vin0 */
+ low_bits = (data->low_bits[0]) & 0x03;
+ break;
+ case 1: /* vin1 */
+ low_bits = ((data->low_bits[0]) & 0x0c) >> 2;
+ break;
+ case 2: /* vin2 */
+ low_bits = ((data->low_bits[0]) & 0x30) >> 4;
+ break;
+ case 3: /* vin3 */
+ low_bits = ((data->low_bits[0]) & 0xc0) >> 6;
+ break;
+ case 4: /* vin4 */
+ low_bits = (data->low_bits[1]) & 0x03;
+ break;
+ case 5: /* vin5 */
+ low_bits = ((data->low_bits[1]) & 0x0c) >> 2;
+ break;
+ case 6: /* vin6 */
+ low_bits = ((data->low_bits[1]) & 0x30) >> 4;
+ default:
+ break;
+ }
+ vol_count = vol_count | low_bits;
+ return vol_count;
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data))));
+}
+
+#define show_in_reg(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ struct w83792d_data *data = w83792d_update_device(dev); \
+ return sprintf(buf,"%ld\n", (long)(IN_FROM_REG(nr, (data->reg[nr])*4))); \
+}
+
+show_in_reg(in_min);
+show_in_reg(in_max);
+
+#define store_in_reg(REG, reg) \
+static ssize_t store_in_##reg (struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83792d_data *data = i2c_get_clientdata(client); \
+ u32 val; \
+ \
+ val = simple_strtoul(buf, NULL, 10); \
+ data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \
+ w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \
+ \
+ return count; \
+}
+store_in_reg(MIN, min);
+store_in_reg(MAX, max);
+
+#define sysfs_in_reg(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \
+ NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, store_in_max, offset);
+
+sysfs_in_reg(0);
+sysfs_in_reg(1);
+sysfs_in_reg(2);
+sysfs_in_reg(3);
+sysfs_in_reg(4);
+sysfs_in_reg(5);
+sysfs_in_reg(6);
+sysfs_in_reg(7);
+sysfs_in_reg(8);
+
+#define device_create_file_in(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_in##offset##_min.dev_attr); \
+} while (0)
+
+#define show_fan_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index - 1; \
+ struct w83792d_data *data = w83792d_update_device(dev); \
+ return sprintf(buf,"%d\n", \
+ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \
+}
+
+show_fan_reg(fan);
+show_fan_reg(fan_min);
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83792d_write_value(client, W83792D_REG_FAN_MIN[nr],
+ data->fan_min[nr]);
+
+ return count;
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+ determined in part by the fan divisor. This follows the principle of
+ least suprise; the user doesn't expect the fan minimum to change just
+ because the divisor changed. */
+static ssize_t
+store_fan_div(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ unsigned long min;
+ /*u8 reg;*/
+ u8 fan_div_reg = 0;
+ u8 tmp_fan_div;
+
+ /* Save fan_min */
+ min = FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr]));
+
+ data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
+
+ fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]);
+ fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8;
+ tmp_fan_div = (nr & 0x01) ? (((data->fan_div[nr]) << 4) & 0x70)
+ : ((data->fan_div[nr]) & 0x07);
+ w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1],
+ fan_div_reg | tmp_fan_div);
+
+ /* Restore fan_min */
+ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], data->fan_min[nr]);
+
+ return count;
+}
+
+#define sysfs_fan(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \
+ offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, store_fan_div, offset); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, store_fan_min, offset);
+
+sysfs_fan(1);
+sysfs_fan(2);
+sysfs_fan(3);
+sysfs_fan(4);
+sysfs_fan(5);
+sysfs_fan(6);
+sysfs_fan(7);
+
+#define device_create_file_fan(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_div.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_fan##offset##_min.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature1, includes measured value and limits */
+
+static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp1[nr]));
+}
+
+static ssize_t store_temp1(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+
+ data->temp1[nr] = TEMP1_TO_REG(val);
+ w83792d_write_value(client, W83792D_REG_TEMP1[nr],
+ data->temp1[nr]);
+
+ return count;
+}
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1,
+ store_temp1, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1,
+ store_temp1, 2);
+
+#define device_create_file_temp1(client) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp1_max_hyst.dev_attr); \
+} while (0)
+
+
+/* read/write the temperature2-3, includes measured value and limits */
+
+static ssize_t show_temp23(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf,"%ld\n",
+ (long)TEMP_ADD_FROM_REG(data->temp_add[nr][index],
+ data->temp_add[nr][index+1]));
+}
+
+static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+
+ data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val);
+ data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val);
+ w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index],
+ data->temp_add[nr][index]);
+ w83792d_write_value(client, W83792D_REG_TEMP_ADD[nr][index+1],
+ data->temp_add[nr][index+1]);
+
+ return count;
+}
+
+#define sysfs_temp23(name,idx) \
+static SENSOR_DEVICE_ATTR_2(name##_input, S_IRUGO, show_temp23, NULL, \
+ idx, 0); \
+static SENSOR_DEVICE_ATTR_2(name##_max, S_IRUGO | S_IWUSR, \
+ show_temp23, store_temp23, idx, 2); \
+static SENSOR_DEVICE_ATTR_2(name##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp23, store_temp23, idx, 4);
+
+sysfs_temp23(temp2,0)
+sysfs_temp23(temp3,1)
+
+#define device_create_file_temp_add(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_input.dev_attr); \
+device_create_file(&client->dev, &sensor_dev_attr_temp##offset##_max.dev_attr); \
+device_create_file(&client->dev, \
+&sensor_dev_attr_temp##offset##_max_hyst.dev_attr); \
+} while (0)
+
+
+/* get reatime status of all sensors items: voltage, temp, fan */
+static ssize_t
+show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->alarms);
+}
+
+static
+DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+#define device_create_file_alarms(client) \
+device_create_file(&client->dev, &dev_attr_alarms);
+
+
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr-1]));
+}
+
+static ssize_t
+show_pwmenable(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ long pwm_enable_tmp = 1;
+
+ switch (data->pwmenable[nr]) {
+ case 0:
+ pwm_enable_tmp = 1; /* manual mode */
+ break;
+ case 1:
+ pwm_enable_tmp = 3; /*thermal cruise/Smart Fan I */
+ break;
+ case 2:
+ pwm_enable_tmp = 2; /* Smart Fan II */
+ break;
+ }
+
+ return sprintf(buf, "%ld\n", pwm_enable_tmp);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->pwm[nr] = PWM_TO_REG(val);
+ w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
+
+ return count;
+}
+
+static ssize_t
+store_pwmenable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
+
+ val = simple_strtoul(buf, NULL, 10);
+ switch (val) {
+ case 1:
+ data->pwmenable[nr] = 0; /* manual mode */
+ break;
+ case 2:
+ data->pwmenable[nr] = 2; /* Smart Fan II */
+ break;
+ case 3:
+ data->pwmenable[nr] = 1; /* thermal cruise/Smart Fan I */
+ break;
+ default:
+ return -EINVAL;
+ }
+ cfg1_tmp = data->pwmenable[0];
+ cfg2_tmp = (data->pwmenable[1]) << 2;
+ cfg3_tmp = (data->pwmenable[2]) << 4;
+ cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0;
+ fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp;
+ w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp);
+
+ return count;
+}
+
+#define sysfs_pwm(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ show_pwm, store_pwm, offset); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+ show_pwmenable, store_pwmenable, offset); \
+
+sysfs_pwm(1);
+sysfs_pwm(2);
+sysfs_pwm(3);
+
+
+#define device_create_file_pwm(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset.dev_attr); \
+} while (0)
+
+#define device_create_file_pwmenable(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_enable.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_mode[nr-1]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 pwm_mode_mask = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->pwm_mode[nr] = SENSORS_LIMIT(val, 0, 1);
+ pwm_mode_mask = w83792d_read_value(client,
+ W83792D_REG_PWM[nr]) & 0x7f;
+ w83792d_write_value(client, W83792D_REG_PWM[nr],
+ ((data->pwm_mode[nr]) << 7) | pwm_mode_mask);
+
+ return count;
+}
+
+#define sysfs_pwm_mode(offset) \
+static SENSOR_DEVICE_ATTR(pwm##offset##_mode, S_IRUGO | S_IWUSR, \
+ show_pwm_mode, store_pwm_mode, offset);
+
+sysfs_pwm_mode(1);
+sysfs_pwm_mode(2);
+sysfs_pwm_mode(3);
+
+#define device_create_file_pwm_mode(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_pwm##offset##_mode.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_regs_chassis(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->chassis);
+}
+
+static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+
+#define device_create_file_chassis(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis); \
+} while (0)
+
+
+static ssize_t
+show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", data->chassis_clear);
+}
+
+static ssize_t
+store_chassis_clear(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 temp1 = 0, temp2 = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+
+ data->chassis_clear = SENSORS_LIMIT(val, 0 ,1);
+ temp1 = ((data->chassis_clear) << 7) & 0x80;
+ temp2 = w83792d_read_value(client,
+ W83792D_REG_CHASSIS_CLR) & 0x7f;
+ w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, temp1 | temp2);
+
+ return count;
+}
+
+static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+ show_chassis_clear, store_chassis_clear);
+
+#define device_create_file_chassis_clear(client) \
+do { \
+device_create_file(&client->dev, &dev_attr_chassis_clear); \
+} while (0)
+
+
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t
+show_thermal_cruise(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->thermal_cruise[nr-1]);
+}
+
+static ssize_t
+store_thermal_cruise(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 target_tmp=0, target_mask=0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ target_tmp = val;
+ target_tmp = target_tmp & 0x7f;
+ target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80;
+ data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255);
+ w83792d_write_value(client, W83792D_REG_THERMAL[nr],
+ (data->thermal_cruise[nr]) | target_mask);
+
+ return count;
+}
+
+#define sysfs_thermal_cruise(offset) \
+static SENSOR_DEVICE_ATTR(thermal_cruise##offset, S_IRUGO | S_IWUSR, \
+ show_thermal_cruise, store_thermal_cruise, offset);
+
+sysfs_thermal_cruise(1);
+sysfs_thermal_cruise(2);
+sysfs_thermal_cruise(3);
+
+#define device_create_file_thermal_cruise(client, offset) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_thermal_cruise##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan I/Thermal Cruise and Smart Fan II */
+static ssize_t
+show_tolerance(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->tolerance[nr-1]);
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 tol_tmp, tol_mask;
+
+ val = simple_strtoul(buf, NULL, 10);
+ tol_mask = w83792d_read_value(client,
+ W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
+ tol_tmp = SENSORS_LIMIT(val, 0, 15);
+ tol_tmp &= 0x0f;
+ data->tolerance[nr] = tol_tmp;
+ if (nr == 1) {
+ tol_tmp <<= 4;
+ }
+ w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
+ tol_mask | tol_tmp);
+
+ return count;
+}
+
+#define sysfs_tolerance(offset) \
+static SENSOR_DEVICE_ATTR(tolerance##offset, S_IRUGO | S_IWUSR, \
+ show_tolerance, store_tolerance, offset);
+
+sysfs_tolerance(1);
+sysfs_tolerance(2);
+sysfs_tolerance(3);
+
+#define device_create_file_tolerance(client, offset) \
+do { \
+device_create_file(&client->dev, &sensor_dev_attr_tolerance##offset.dev_attr); \
+} while (0)
+
+
+/* For Smart Fan II */
+static ssize_t
+show_sf2_point(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)data->sf2_points[index-1][nr-1]);
+}
+
+static ssize_t
+store_sf2_point(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr - 1;
+ int index = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 mask_tmp = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127);
+ mask_tmp = w83792d_read_value(client,
+ W83792D_REG_POINTS[index][nr]) & 0x80;
+ w83792d_write_value(client, W83792D_REG_POINTS[index][nr],
+ mask_tmp|data->sf2_points[index][nr]);
+
+ return count;
+}
+
+#define sysfs_sf2_point(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_point##offset##_fan##index, S_IRUGO | S_IWUSR, \
+ show_sf2_point, store_sf2_point, offset, index);
+
+sysfs_sf2_point(1, 1); /* Fan1 */
+sysfs_sf2_point(2, 1); /* Fan1 */
+sysfs_sf2_point(3, 1); /* Fan1 */
+sysfs_sf2_point(4, 1); /* Fan1 */
+sysfs_sf2_point(1, 2); /* Fan2 */
+sysfs_sf2_point(2, 2); /* Fan2 */
+sysfs_sf2_point(3, 2); /* Fan2 */
+sysfs_sf2_point(4, 2); /* Fan2 */
+sysfs_sf2_point(1, 3); /* Fan3 */
+sysfs_sf2_point(2, 3); /* Fan3 */
+sysfs_sf2_point(3, 3); /* Fan3 */
+sysfs_sf2_point(4, 3); /* Fan3 */
+
+#define device_create_file_sf2_point(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_point##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+static ssize_t
+show_sf2_level(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n",
+ (((data->sf2_levels[index-1][nr]) * 100) / 15));
+}
+
+static ssize_t
+store_sf2_level(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr);
+ int nr = sensor_attr->nr;
+ int index = sensor_attr->index - 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ u32 val;
+ u8 mask_tmp=0, level_tmp=0;
+
+ val = simple_strtoul(buf, NULL, 10);
+ data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15);
+ mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr])
+ & ((nr==3) ? 0xf0 : 0x0f);
+ if (nr==3) {
+ level_tmp = data->sf2_levels[index][nr];
+ } else {
+ level_tmp = data->sf2_levels[index][nr] << 4;
+ }
+ w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
+
+ return count;
+}
+
+#define sysfs_sf2_level(offset, index) \
+static SENSOR_DEVICE_ATTR_2(sf2_level##offset##_fan##index, S_IRUGO | S_IWUSR, \
+ show_sf2_level, store_sf2_level, offset, index);
+
+sysfs_sf2_level(1, 1); /* Fan1 */
+sysfs_sf2_level(2, 1); /* Fan1 */
+sysfs_sf2_level(3, 1); /* Fan1 */
+sysfs_sf2_level(1, 2); /* Fan2 */
+sysfs_sf2_level(2, 2); /* Fan2 */
+sysfs_sf2_level(3, 2); /* Fan2 */
+sysfs_sf2_level(1, 3); /* Fan3 */
+sysfs_sf2_level(2, 3); /* Fan3 */
+sysfs_sf2_level(3, 3); /* Fan3 */
+
+#define device_create_file_sf2_level(client, offset, index) \
+do { \
+device_create_file(&client->dev, \
+&sensor_dev_attr_sf2_level##offset##_fan##index.dev_attr); \
+} while (0)
+
+
+/* This function is called when:
+ * w83792d_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and w83792d_driver is still present) */
+static int
+w83792d_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, w83792d_detect);
+}
+
+
+static int
+w83792d_create_subclient(struct i2c_adapter *adapter,
+ struct i2c_client *new_client, int addr,
+ struct i2c_client **sub_cli)
+{
+ int err;
+ struct i2c_client *sub_client;
+
+ (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!(sub_client)) {
+ return -ENOMEM;
+ }
+ memset(sub_client, 0x00, sizeof(struct i2c_client));
+ sub_client->addr = 0x48 + addr;
+ i2c_set_clientdata(sub_client, NULL);
+ sub_client->adapter = adapter;
+ sub_client->driver = &w83792d_driver;
+ sub_client->flags = 0;
+ strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
+ if ((err = i2c_attach_client(sub_client))) {
+ dev_err(&new_client->dev, "subclient registration "
+ "at address 0x%x failed\n", sub_client->addr);
+ kfree(sub_client);
+ return err;
+ }
+ return 0;
+}
+
+
+static int
+w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_client *new_client)
+{
+ int i, id, err;
+ u8 val;
+ struct w83792d_data *data = i2c_get_clientdata(new_client);
+
+ id = i2c_adapter_id(adapter);
+ if (force_subclients[0] == id && force_subclients[1] == address) {
+ for (i = 2; i <= 3; i++) {
+ if (force_subclients[i] < 0x48 ||
+ force_subclients[i] > 0x4f) {
+ dev_err(&new_client->dev, "invalid subclient "
+ "address %d; must be 0x48-0x4f\n",
+ force_subclients[i]);
+ err = -ENODEV;
+ goto ERROR_SC_0;
+ }
+ }
+ w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
+ (force_subclients[2] & 0x07) |
+ ((force_subclients[3] & 0x07) << 4));
+ }
+
+ val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
+ if (!(val & 0x08)) {
+ err = w83792d_create_subclient(adapter, new_client, val & 0x7,
+ &data->lm75[0]);
+ if (err < 0)
+ goto ERROR_SC_0;
+ }
+ if (!(val & 0x80)) {
+ if ((data->lm75[0] != NULL) &&
+ ((val & 0x7) == ((val >> 4) & 0x7))) {
+ dev_err(&new_client->dev, "duplicate addresses 0x%x, "
+ "use force_subclient\n", data->lm75[0]->addr);
+ err = -ENODEV;
+ goto ERROR_SC_1;
+ }
+ err = w83792d_create_subclient(adapter, new_client,
+ (val >> 4) & 0x7, &data->lm75[1]);
+ if (err < 0)
+ goto ERROR_SC_1;
+ }
+
+ return 0;
+
+/* Undo inits in case of errors */
+
+ERROR_SC_1:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ERROR_SC_0:
+ return err;
+}
+
+
+static int
+w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ int i = 0, val1 = 0, val2;
+ struct i2c_client *new_client;
+ struct w83792d_data *data;
+ int err = 0;
+ const char *client_name = "";
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto ERROR0;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access w83792d_{read,write}_value. */
+
+ if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+ memset(data, 0, sizeof(struct w83792d_data));
+
+ new_client = &data->client;
+ i2c_set_clientdata(new_client, data);
+ new_client->addr = address;
+ init_MUTEX(&data->lock);
+ new_client->adapter = adapter;
+ new_client->driver = &w83792d_driver;
+ new_client->flags = 0;
+
+ /* Now, we do the remaining detection. */
+
+ /* The w83792d may be stuck in some other bank than bank 0. This may
+ make reading other information impossible. Specify a force=... or
+ force_*=... parameter, and the Winbond will be reset to the right
+ bank. */
+ if (kind < 0) {
+ if (w83792d_read_value(new_client, W83792D_REG_CONFIG) & 0x80) {
+ dev_warn(&new_client->dev, "Detection failed at step "
+ "3\n");
+ goto ERROR1;
+ }
+ val1 = w83792d_read_value(new_client, W83792D_REG_BANK);
+ val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+ /* Check for Winbond ID if in bank 0 */
+ if (!(val1 & 0x07)) { /* is Bank0 */
+ if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
+ ((val1 & 0x80) && (val2 != 0x5c))) {
+ goto ERROR1;
+ }
+ }
+ /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
+ should match */
+ if (w83792d_read_value(new_client,
+ W83792D_REG_I2C_ADDR) != address) {
+ dev_warn(&new_client->dev, "Detection failed "
+ "at step 5\n");
+ goto ERROR1;
+ }
+ }
+
+ /* We have either had a force parameter, or we have already detected the
+ Winbond. Put it now into bank 0 and Vendor ID High Byte */
+ w83792d_write_value(new_client,
+ W83792D_REG_BANK,
+ (w83792d_read_value(new_client,
+ W83792D_REG_BANK) & 0x78) | 0x80);
+
+ /* Determine the chip type. */
+ if (kind <= 0) {
+ /* get vendor ID */
+ val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN);
+ if (val2 != 0x5c) { /* the vendor is NOT Winbond */
+ goto ERROR1;
+ }
+ val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID);
+ if (val1 == 0x7a && address >= 0x2c) {
+ kind = w83792d;
+ } else {
+ if (kind == 0)
+ dev_warn(&new_client->dev,
+ "w83792d: Ignoring 'force' parameter for"
+ " unknown chip at adapter %d, address"
+ " 0x%02x\n", i2c_adapter_id(adapter),
+ address);
+ goto ERROR1;
+ }
+ }
+
+ if (kind == w83792d) {
+ client_name = "w83792d";
+ } else {
+ dev_err(&new_client->dev, "w83792d: Internal error: unknown"
+ " kind (%d)?!?", kind);
+ goto ERROR1;
+ }
+
+ /* Fill in the remaining client fields and put into the global list */
+ strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+ data->type = kind;
+
+ data->valid = 0;
+ init_MUTEX(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(new_client)))
+ goto ERROR1;
+
+ if ((err = w83792d_detect_subclients(adapter, address,
+ kind, new_client)))
+ goto ERROR2;
+
+ /* Initialize the chip */
+ w83792d_init_client(new_client);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 1; i <= 7; i++) {
+ data->fan_min[i - 1] = w83792d_read_value(new_client,
+ W83792D_REG_FAN_MIN[i]);
+ }
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
+ device_create_file_in(new_client, 0);
+ device_create_file_in(new_client, 1);
+ device_create_file_in(new_client, 2);
+ device_create_file_in(new_client, 3);
+ device_create_file_in(new_client, 4);
+ device_create_file_in(new_client, 5);
+ device_create_file_in(new_client, 6);
+ device_create_file_in(new_client, 7);
+ device_create_file_in(new_client, 8);
+
+ device_create_file_fan(new_client, 1);
+ device_create_file_fan(new_client, 2);
+ device_create_file_fan(new_client, 3);
+ device_create_file_fan(new_client, 4);
+ device_create_file_fan(new_client, 5);
+ device_create_file_fan(new_client, 6);
+ device_create_file_fan(new_client, 7);
+
+ device_create_file_temp1(new_client); /* Temp1 */
+ device_create_file_temp_add(new_client, 2); /* Temp2 */
+ device_create_file_temp_add(new_client, 3); /* Temp3 */
+
+ device_create_file_alarms(new_client);
+
+ device_create_file_pwm(new_client, 1);
+ device_create_file_pwm(new_client, 2);
+ device_create_file_pwm(new_client, 3);
+
+ device_create_file_pwmenable(new_client, 1);
+ device_create_file_pwmenable(new_client, 2);
+ device_create_file_pwmenable(new_client, 3);
+
+ device_create_file_pwm_mode(new_client, 1);
+ device_create_file_pwm_mode(new_client, 2);
+ device_create_file_pwm_mode(new_client, 3);
+
+ device_create_file_chassis(new_client);
+ device_create_file_chassis_clear(new_client);
+
+ device_create_file_thermal_cruise(new_client, 1);
+ device_create_file_thermal_cruise(new_client, 2);
+ device_create_file_thermal_cruise(new_client, 3);
+
+ device_create_file_tolerance(new_client, 1);
+ device_create_file_tolerance(new_client, 2);
+ device_create_file_tolerance(new_client, 3);
+
+ device_create_file_sf2_point(new_client, 1, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 2, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 3, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 4, 1); /* Fan1 */
+ device_create_file_sf2_point(new_client, 1, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 2, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 3, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 4, 2); /* Fan2 */
+ device_create_file_sf2_point(new_client, 1, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 2, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 3, 3); /* Fan3 */
+ device_create_file_sf2_point(new_client, 4, 3); /* Fan3 */
+
+ device_create_file_sf2_level(new_client, 1, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 2, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 3, 1); /* Fan1 */
+ device_create_file_sf2_level(new_client, 1, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 2, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 3, 2); /* Fan2 */
+ device_create_file_sf2_level(new_client, 1, 3); /* Fan3 */
+ device_create_file_sf2_level(new_client, 2, 3); /* Fan3 */
+ device_create_file_sf2_level(new_client, 3, 3); /* Fan3 */
+
+ return 0;
+
+ERROR3:
+ if (data->lm75[0] != NULL) {
+ i2c_detach_client(data->lm75[0]);
+ kfree(data->lm75[0]);
+ }
+ if (data->lm75[1] != NULL) {
+ i2c_detach_client(data->lm75[1]);
+ kfree(data->lm75[1]);
+ }
+ERROR2:
+ i2c_detach_client(new_client);
+ERROR1:
+ kfree(data);
+ERROR0:
+ return err;
+}
+
+static int
+w83792d_detach_client(struct i2c_client *client)
+{
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ int err;
+
+ /* main client */
+ if (data)
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ /* main client */
+ if (data)
+ kfree(data);
+ /* subclient */
+ else
+ kfree(client);
+
+ return 0;
+}
+
+/* The SMBus locks itself, usually, but nothing may access the Winbond between
+ bank switches. ISA access must always be locked explicitly!
+ We ignore the W83792D BUSY flag at this moment - it could lead to deadlocks,
+ would slow down the W83792D access and should not be necessary.
+ There are some ugly typecasts here, but the good news is - they should
+ nowhere else be necessary! */
+static int
+w83792d_read_value(struct i2c_client *client, u8 reg)
+{
+ int res=0;
+ res = i2c_smbus_read_byte_data(client, reg);
+
+ return res;
+}
+
+static int
+w83792d_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+ i2c_smbus_write_byte_data(client, reg, value);
+ return 0;
+}
+
+/* Called when we have found a new W83792D. It should set limits, etc. */
+static void
+w83792d_init_client(struct i2c_client *client)
+{
+ u8 temp2_cfg, temp3_cfg, vid_in_b;
+
+ if (init) {
+ w83792d_write_value(client, W83792D_REG_CONFIG, 0x80);
+ }
+ /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0):
+ W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of
+ vin0/vin1 can be modified by user;
+ W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of
+ vin0/vin1 auto-updated, can NOT be modified by user. */
+ vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B);
+ w83792d_write_value(client, W83792D_REG_VID_IN_B,
+ vid_in_b & 0xbf);
+
+ temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP2_CONFIG);
+ temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP3_CONFIG);
+ w83792d_write_value(client, W83792D_REG_TEMP2_CONFIG,
+ temp2_cfg & 0xe6);
+ w83792d_write_value(client, W83792D_REG_TEMP3_CONFIG,
+ temp3_cfg & 0xe6);
+
+ /* Start monitoring */
+ w83792d_write_value(client, W83792D_REG_CONFIG,
+ (w83792d_read_value(client,
+ W83792D_REG_CONFIG) & 0xf7)
+ | 0x01);
+}
+
+static struct w83792d_data *w83792d_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+ int i, j;
+ u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp;
+
+ down(&data->update_lock);
+
+ if (time_after
+ (jiffies - data->last_updated, (unsigned long) (HZ * 3))
+ || time_before(jiffies, data->last_updated) || !data->valid) {
+ dev_dbg(dev, "Starting device update\n");
+
+ /* Update the voltages measured value and limits */
+ for (i = 0; i < 9; i++) {
+ data->in[i] = w83792d_read_value(client,
+ W83792D_REG_IN[i]);
+ data->in_max[i] = w83792d_read_value(client,
+ W83792D_REG_IN_MAX[i]);
+ data->in_min[i] = w83792d_read_value(client,
+ W83792D_REG_IN_MIN[i]);
+ }
+ data->low_bits[0] = w83792d_read_value(client,
+ W83792D_REG_LOW_BITS1);
+ data->low_bits[1] = w83792d_read_value(client,
+ W83792D_REG_LOW_BITS2);
+ for (i = 0; i < 7; i++) {
+ /* Update the Fan measured value and limits */
+ data->fan[i] = w83792d_read_value(client,
+ W83792D_REG_FAN[i]);
+ data->fan_min[i] = w83792d_read_value(client,
+ W83792D_REG_FAN_MIN[i]);
+ /* Update the PWM/DC Value and PWM/DC flag */
+ pwm_array_tmp[i] = w83792d_read_value(client,
+ W83792D_REG_PWM[i]);
+ data->pwm[i] = pwm_array_tmp[i] & 0x0f;
+ data->pwm_mode[i] = (pwm_array_tmp[i] >> 7) & 0x01;
+ }
+
+ reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
+ data->pwmenable[0] = reg_tmp & 0x03;
+ data->pwmenable[1] = (reg_tmp>>2) & 0x03;
+ data->pwmenable[2] = (reg_tmp>>4) & 0x03;
+
+ for (i = 0; i < 3; i++) {
+ data->temp1[i] = w83792d_read_value(client,
+ W83792D_REG_TEMP1[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 6; j++) {
+ data->temp_add[i][j] = w83792d_read_value(
+ client,W83792D_REG_TEMP_ADD[i][j]);
+ }
+ }
+
+ /* Update the Fan Divisor */
+ for (i = 0; i < 4; i++) {
+ reg_array_tmp[i] = w83792d_read_value(client,
+ W83792D_REG_FAN_DIV[i]);
+ }
+ data->fan_div[0] = reg_array_tmp[0] & 0x07;
+ data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07;
+ data->fan_div[2] = reg_array_tmp[1] & 0x07;
+ data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07;
+ data->fan_div[4] = reg_array_tmp[2] & 0x07;
+ data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07;
+ data->fan_div[6] = reg_array_tmp[3] & 0x07;
+
+ /* Update the realtime status */
+ data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) +
+ (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) +
+ (w83792d_read_value(client, W83792D_REG_ALARM3) << 16);
+
+ /* Update CaseOpen status and it's CLR_CHS. */
+ data->chassis = (w83792d_read_value(client,
+ W83792D_REG_CHASSIS) >> 5) & 0x01;
+ data->chassis_clear = (w83792d_read_value(client,
+ W83792D_REG_CHASSIS_CLR) >> 7) & 0x01;
+
+ /* Update Thermal Cruise/Smart Fan I target value */
+ for (i = 0; i < 3; i++) {
+ data->thermal_cruise[i] =
+ w83792d_read_value(client,
+ W83792D_REG_THERMAL[i]) & 0x7f;
+ }
+
+ /* Update Smart Fan I/II tolerance */
+ reg_tmp = w83792d_read_value(client, W83792D_REG_TOLERANCE[0]);
+ data->tolerance[0] = reg_tmp & 0x0f;
+ data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
+ data->tolerance[2] = w83792d_read_value(client,
+ W83792D_REG_TOLERANCE[2]) & 0x0f;
+
+ /* Update Smart Fan II temperature points */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 4; j++) {
+ data->sf2_points[i][j] = w83792d_read_value(
+ client,W83792D_REG_POINTS[i][j]) & 0x7f;
+ }
+ }
+
+ /* Update Smart Fan II duty cycle levels */
+ for (i = 0; i < 3; i++) {
+ reg_tmp = w83792d_read_value(client,
+ W83792D_REG_LEVELS[i][0]);
+ data->sf2_levels[i][0] = reg_tmp & 0x0f;
+ data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f;
+ reg_tmp = w83792d_read_value(client,
+ W83792D_REG_LEVELS[i][2]);
+ data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f;
+ data->sf2_levels[i][3] = reg_tmp & 0x0f;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ up(&data->update_lock);
+
+#ifdef DEBUG
+ w83792d_print_debug(data, dev);
+#endif
+
+ return data;
+}
+
+#ifdef DEBUG
+static void w83792d_print_debug(struct w83792d_data *data, struct device *dev)
+{
+ int i=0, j=0;
+ dev_dbg(dev, "==========The following is the debug message...========\n");
+ dev_dbg(dev, "9 set of Voltages: =====>\n");
+ for (i=0; i<9; i++) {
+ dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]);
+ dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]);
+ dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]);
+ }
+ dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits[0]);
+ dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits[1]);
+ dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n");
+ for (i=0; i<7; i++) {
+ dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]);
+ dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]);
+ dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]);
+ dev_dbg(dev, "pwm_mode[%d] is: 0x%x\n", i, data->pwm_mode[i]);
+ }
+ dev_dbg(dev, "3 set of Temperatures: =====>\n");
+ for (i=0; i<3; i++) {
+ dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]);
+ }
+
+ for (i=0; i<2; i++) {
+ for (j=0; j<6; j++) {
+ dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j,
+ data->temp_add[i][j]);
+ }
+ }
+
+ for (i=0; i<7; i++) {
+ dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]);
+ }
+ dev_dbg(dev, "==========End of the debug message...==================\n");
+ dev_dbg(dev, "\n");
+}
+#endif
+
+static int __init
+sensors_w83792d_init(void)
+{
+ return i2c_add_driver(&w83792d_driver);
+}
+
+static void __exit
+sensors_w83792d_exit(void)
+{
+ i2c_del_driver(&w83792d_driver);
+}
+
+MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>");
+MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83792d_init);
+module_exit(sensors_w83792d_exit);
+
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 4469d52aba4c..133e34ab1d0a 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -36,7 +36,8 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
/* How many retries on register read error */
#define MAX_RETRIES 5
@@ -47,13 +48,12 @@
*/
static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
-SENSORS_INSMOD_1(w83l785ts);
+I2C_CLIENT_INSMOD_1(w83l785ts);
/*
* The W83L785TS-S registers
@@ -105,6 +105,7 @@ static struct i2c_driver w83l785ts_driver = {
struct w83l785ts_data {
struct i2c_client client;
+ struct class_device *class_dev;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -140,7 +141,7 @@ static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, w83l785ts_detect);
+ return i2c_probe(adapter, &addr_data, w83l785ts_detect);
}
/*
@@ -239,11 +240,19 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
*/
/* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_detach;
+ }
+
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_max);
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -252,15 +261,15 @@ exit:
static int w83l785ts_detach_client(struct i2c_client *client)
{
+ struct w83l785ts_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}