Browse Source

Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6

* 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6:
  hwmon: (i5k_amb) Convert macros to C functions
  hwmon: (w83781d) Add missing curly braces
  hwmon: (abituguru3) Identify ABit IP35 Pro as such
  hwmon: (f75375s) pwmX_mode sysfs files writable for f75375 variant
  hwmon: (f75375s) On n2100 systems, set fans to full speed on boot
  hwmon: (f75375s) Allow setting up fans with platform_data
  hwmon: (f75375s) Add new style bindings
  hwmon: (lm70) Convert semaphore to mutex
  hwmon: (applesmc) Add support for Mac Pro 2 x Quad-Core
  hwmon: (abituguru3) Add support for 2 new motherboards
  hwmon: (ibmpex) Change printk to dev_{info,err} macros
  hwmon: (i5k_amb) New memory temperature sensor driver
  hwmon: (f75375s) fix pwm mode setting
  hwmon: (ibmpex.c) fix NULL dereference
  hwmon: (sis5595) Split sis5595_attributes_opt
  hwmon: (sis5595) Add individual alarm files
  hwmon: (w83627hf) push nr+1 offset into *_REG_FAN macros and simplify
  hwmon: (w83627hf) hoist nr-1 offset out of show-store-temp-X
  hwmon: Add power meter spec to Documentation/hwmon/sysfs-interface
Linus Torvalds 17 years ago
parent
commit
9418d5dc9b

+ 31 - 0
Documentation/hwmon/sysfs-interface

@@ -328,6 +328,37 @@ curr[1-*]_input	Current input value
 		Unit: milliampere
 		RO
 
+*********
+* Power *
+*********
+
+power[1-*]_average		Average power use
+				Unit: microWatt
+				RO
+
+power[1-*]_average_highest	Historical average maximum power use
+				Unit: microWatt
+				RO
+
+power[1-*]_average_lowest	Historical average minimum power use
+				Unit: microWatt
+				RO
+
+power[1-*]_input		Instantaneous power use
+				Unit: microWatt
+				RO
+
+power[1-*]_input_highest	Historical maximum power use
+				Unit: microWatt
+				RO
+
+power[1-*]_input_lowest		Historical minimum power use
+				Unit: microWatt
+				RO
+
+power[1-*]_reset_history	Reset input_highest, input_lowest,
+				average_highest and average_lowest.
+				WO
 
 **********
 * Alarms *

+ 11 - 0
arch/arm/mach-iop32x/n2100.c

@@ -16,6 +16,7 @@
 
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/f75375s.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -200,11 +201,21 @@ static struct platform_device n2100_serial_device = {
 	.resource	= &n2100_uart_resource,
 };
 
+static struct f75375s_platform_data n2100_f75375s = {
+	.pwm		= { 255, 255 },
+	.pwm_enable = { 0, 0 },
+};
+
 static struct i2c_board_info __initdata n2100_i2c_devices[] = {
 	{
 		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
 		.type = "rs5c372b",
 	},
+	{
+		I2C_BOARD_INFO("f75375", 0x2e),
+		.type = "f75375",
+		.platform_data = &n2100_f75375s,
+	},
 };
 
 /*

+ 10 - 0
drivers/hwmon/Kconfig

@@ -216,6 +216,16 @@ config SENSORS_DS1621
 	  This driver can also be built as a module.  If so, the module
 	  will be called ds1621.
 
+config SENSORS_I5K_AMB
+	tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
+	depends on PCI && EXPERIMENTAL
+	help
+	  If you say yes here you get support for FB-DIMM AMB temperature
+	  monitoring chips on systems with the Intel 5000 series chipset.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i5k_amb.
+
 config SENSORS_F71805F
 	tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
 	depends on EXPERIMENTAL

+ 1 - 0
drivers/hwmon/Makefile

@@ -38,6 +38,7 @@ 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_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
 obj-$(CONFIG_SENSORS_K8TEMP)	+= k8temp.o

+ 55 - 1
drivers/hwmon/abituguru3.c

@@ -503,7 +503,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
 		{ "AUX3 FAN",		36, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
-	{ 0x001A, "unknown", {
+	{ 0x001A, "Abit IP35 Pro", {
 		{ "CPU Core",		 0, 0, 10, 1, 0 },
 		{ "DDR2",		 1, 0, 20, 1, 0 },
 		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
@@ -530,6 +530,60 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
 		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
 		{ NULL, 0, 0, 0, 0, 0 } }
 	},
+	{ 0x001B, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR3",		 1, 0, 20, 1, 0 },
+		{ "DDR3 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x001C, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
 	{ 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
 };
 

+ 101 - 6
drivers/hwmon/applesmc.c

@@ -80,7 +80,7 @@
 /*
  * Temperature sensors keys (sp78 - 2 bytes).
  */
-static const char* temperature_sensors_sets[][13] = {
+static const char* temperature_sensors_sets[][36] = {
 /* Set 0: Macbook Pro */
 	{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
 	  "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
@@ -88,7 +88,13 @@ static const char* temperature_sensors_sets[][13] = {
 	{ "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
 	  "Th1H", "Ts0P", NULL },
 /* Set 2: Macmini set */
-	{ "TC0D", "TC0P", NULL }
+	{ "TC0D", "TC0P", NULL },
+/* Set 3: Mac Pro (2 x Quad-Core) */
+	{ "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
+	  "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
+	  "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
+	  "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
+	  "TM9S", "TN0H", "TS0C", NULL },
 };
 
 /* List of keys used to read/write fan speeds */
@@ -990,14 +996,18 @@ static struct attribute *fan##offset##_attributes[] = { \
 
 /*
  * Create the needed functions for each fan using the macro defined above
- * (2 fans are supported)
+ * (4 fans are supported)
  */
 sysfs_fan_speeds_offset(1);
 sysfs_fan_speeds_offset(2);
+sysfs_fan_speeds_offset(3);
+sysfs_fan_speeds_offset(4);
 
 static const struct attribute_group fan_attribute_groups[] = {
 	{ .attrs = fan1_attributes },
-	{ .attrs = fan2_attributes }
+	{ .attrs = fan2_attributes },
+	{ .attrs = fan3_attributes },
+	{ .attrs = fan4_attributes },
 };
 
 /*
@@ -1027,6 +1037,52 @@ static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 10);
 static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 24);
+static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 25);
+static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 26);
+static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 27);
+static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 28);
+static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 29);
+static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 30);
+static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 31);
+static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 32);
+static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 33);
+static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 34);
 
 static struct attribute *temperature_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -1041,6 +1097,29 @@ static struct attribute *temperature_attributes[] = {
 	&sensor_dev_attr_temp10_input.dev_attr.attr,
 	&sensor_dev_attr_temp11_input.dev_attr.attr,
 	&sensor_dev_attr_temp12_input.dev_attr.attr,
+	&sensor_dev_attr_temp13_input.dev_attr.attr,
+	&sensor_dev_attr_temp14_input.dev_attr.attr,
+	&sensor_dev_attr_temp15_input.dev_attr.attr,
+	&sensor_dev_attr_temp16_input.dev_attr.attr,
+	&sensor_dev_attr_temp17_input.dev_attr.attr,
+	&sensor_dev_attr_temp18_input.dev_attr.attr,
+	&sensor_dev_attr_temp19_input.dev_attr.attr,
+	&sensor_dev_attr_temp20_input.dev_attr.attr,
+	&sensor_dev_attr_temp21_input.dev_attr.attr,
+	&sensor_dev_attr_temp22_input.dev_attr.attr,
+	&sensor_dev_attr_temp23_input.dev_attr.attr,
+	&sensor_dev_attr_temp24_input.dev_attr.attr,
+	&sensor_dev_attr_temp25_input.dev_attr.attr,
+	&sensor_dev_attr_temp26_input.dev_attr.attr,
+	&sensor_dev_attr_temp27_input.dev_attr.attr,
+	&sensor_dev_attr_temp28_input.dev_attr.attr,
+	&sensor_dev_attr_temp29_input.dev_attr.attr,
+	&sensor_dev_attr_temp30_input.dev_attr.attr,
+	&sensor_dev_attr_temp31_input.dev_attr.attr,
+	&sensor_dev_attr_temp32_input.dev_attr.attr,
+	&sensor_dev_attr_temp33_input.dev_attr.attr,
+	&sensor_dev_attr_temp34_input.dev_attr.attr,
+	&sensor_dev_attr_temp35_input.dev_attr.attr,
 	NULL
 };
 
@@ -1137,6 +1216,8 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
 	{ .accelerometer = 1, .light = 0, .temperature_set = 1 },
 /* MacMini: temperature set 2 */
 	{ .accelerometer = 0, .light = 0, .temperature_set = 2 },
+/* MacPro: temperature set 3 */
+	{ .accelerometer = 0, .light = 0, .temperature_set = 3 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1154,6 +1235,10 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
 	  DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
 	  DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
 		(void*)&applesmc_dmi_data[2]},
+	{ applesmc_dmi_match, "Apple MacPro2", {
+	  DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
+		(void*)&applesmc_dmi_data[3]},
 	{ .ident = NULL }
 };
 
@@ -1204,9 +1289,19 @@ static int __init applesmc_init(void)
 
 		switch (count) {
 		default:
-			printk(KERN_WARNING "applesmc: More than 2 fans found,"
-					" but at most 2 fans are supported"
+			printk(KERN_WARNING "applesmc: More than 4 fans found,"
+					" but at most 4 fans are supported"
 						" by the driver.\n");
+		case 4:
+			ret = sysfs_create_group(&pdev->dev.kobj,
+						 &fan_attribute_groups[3]);
+			if (ret)
+				goto out_key_enumeration;
+		case 3:
+			ret = sysfs_create_group(&pdev->dev.kobj,
+						 &fan_attribute_groups[2]);
+			if (ret)
+				goto out_key_enumeration;
 		case 2:
 			ret = sysfs_create_group(&pdev->dev.kobj,
 						 &fan_attribute_groups[1]);

+ 134 - 36
drivers/hwmon/f75375s.c

@@ -34,6 +34,7 @@
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/f75375s.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
@@ -86,7 +87,7 @@ I2C_CLIENT_INSMOD_2(f75373, f75375);
 
 struct f75375_data {
 	unsigned short addr;
-	struct i2c_client client;
+	struct i2c_client *client;
 	struct device *hwmon_dev;
 
 	const char *name;
@@ -116,15 +117,25 @@ struct f75375_data {
 static int f75375_attach_adapter(struct i2c_adapter *adapter);
 static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
 static int f75375_detach_client(struct i2c_client *client);
+static int f75375_probe(struct i2c_client *client);
+static int f75375_remove(struct i2c_client *client);
 
-static struct i2c_driver f75375_driver = {
+static struct i2c_driver f75375_legacy_driver = {
 	.driver = {
-		.name = "f75375",
+		.name = "f75375_legacy",
 	},
 	.attach_adapter = f75375_attach_adapter,
 	.detach_client = f75375_detach_client,
 };
 
+static struct i2c_driver f75375_driver = {
+	.driver = {
+		.name = "f75375",
+	},
+	.probe = f75375_probe,
+	.remove = f75375_remove,
+};
+
 static inline int f75375_read8(struct i2c_client *client, u8 reg)
 {
 	return i2c_smbus_read_byte_data(client, reg);
@@ -276,19 +287,14 @@ static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
 	return sprintf(buf, "%d\n", data->pwm_enable[nr]);
 }
 
-static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
 {
-	int nr = to_sensor_dev_attr(attr)->index;
-	struct i2c_client *client = to_i2c_client(dev);
 	struct f75375_data *data = i2c_get_clientdata(client);
-	int val = simple_strtoul(buf, NULL, 10);
 	u8 fanmode;
 
 	if (val < 0 || val > 4)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
 	fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
 	fanmode = ~(3 << FAN_CTRL_MODE(nr));
 
@@ -310,8 +316,22 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
 	}
 	f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
 	data->pwm_enable[nr] = val;
+	return 0;
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct f75375_data *data = i2c_get_clientdata(client);
+	int val = simple_strtoul(buf, NULL, 10);
+	int err = 0;
+
+	mutex_lock(&data->update_lock);
+	err = set_pwm_enable_direct(client, nr, val);
 	mutex_unlock(&data->update_lock);
-	return count;
+	return err ? err : count;
 }
 
 static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
@@ -323,7 +343,7 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
 	int val = simple_strtoul(buf, NULL, 10);
 	u8 conf = 0;
 
-	if (val != 0 || val != 1 || data->kind == f75373)
+	if (!(val == 0 || val == 1))
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
@@ -529,13 +549,13 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
 	show_pwm, set_pwm, 0);
 static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
 	show_pwm_enable, set_pwm_enable, 0);
-static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO,
 	show_pwm_mode, set_pwm_mode, 0);
 static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
 	show_pwm, set_pwm, 1);
 static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
 	show_pwm_enable, set_pwm_enable, 1);
-static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO,
 	show_pwm_mode, set_pwm_mode, 1);
 
 static struct attribute *f75375_attributes[] = {
@@ -580,12 +600,9 @@ static const struct attribute_group f75375_group = {
 
 static int f75375_detach_client(struct i2c_client *client)
 {
-	struct f75375_data *data = i2c_get_clientdata(client);
 	int err;
 
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&client->dev.kobj, &f75375_group);
-
+	f75375_remove(client);
 	err = i2c_detach_client(client);
 	if (err) {
 		dev_err(&client->dev,
@@ -593,7 +610,91 @@ static int f75375_detach_client(struct i2c_client *client)
 			"client not detached.\n");
 		return err;
 	}
+	kfree(client);
+	return 0;
+}
+
+static void f75375_init(struct i2c_client *client, struct f75375_data *data,
+		struct f75375s_platform_data *f75375s_pdata)
+{
+	int nr;
+	set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);
+	set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);
+	for (nr = 0; nr < 2; nr++) {
+		data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
+		f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+			data->pwm[nr]);
+	}
+
+}
+
+static int f75375_probe(struct i2c_client *client)
+{
+	struct f75375_data *data = i2c_get_clientdata(client);
+	struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+	if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL)))
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+	mutex_init(&data->update_lock);
+
+	if (strcmp(client->name, "f75375") == 0)
+		data->kind = f75375;
+	else if (strcmp(client->name, "f75373") == 0)
+		data->kind = f75373;
+	else {
+		dev_err(&client->dev, "Unsupported device: %s\n", client->name);
+		return -ENODEV;
+	}
+
+	if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
+		goto exit_free;
+
+	if (data->kind == f75375) {
+		err = sysfs_chmod_file(&client->dev.kobj,
+			&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+			S_IRUGO | S_IWUSR);
+		if (err)
+			goto exit_remove;
+		err = sysfs_chmod_file(&client->dev.kobj,
+			&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+			S_IRUGO | S_IWUSR);
+		if (err)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	if (f75375s_pdata != NULL)
+		f75375_init(client, data, f75375s_pdata);
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &f75375_group);
+exit_free:
 	kfree(data);
+	i2c_set_clientdata(client, NULL);
+	return err;
+}
+
+static int f75375_remove(struct i2c_client *client)
+{
+	struct f75375_data *data = i2c_get_clientdata(client);
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &f75375_group);
+	kfree(data);
+	i2c_set_clientdata(client, NULL);
 	return 0;
 }
 
@@ -608,20 +709,17 @@ static int f75375_attach_adapter(struct i2c_adapter *adapter)
 static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
 {
 	struct i2c_client *client;
-	struct f75375_data *data;
 	u8 version = 0;
 	int err = 0;
 	const char *name = "";
 
-	if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) {
+	if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto exit;
 	}
-	client = &data->client;
-	i2c_set_clientdata(client, data);
 	client->addr = address;
 	client->adapter = adapter;
-	client->driver = &f75375_driver;
+	client->driver = &f75375_legacy_driver;
 
 	if (kind < 0) {
 		u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
@@ -644,42 +742,42 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
 	} else if (kind == f75373) {
 		name = "f75373";
 	}
-
 	dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
 	strlcpy(client->name, name, I2C_NAME_SIZE);
-	data->kind = kind;
-	mutex_init(&data->update_lock);
+
 	if ((err = i2c_attach_client(client)))
 		goto exit_free;
 
-	if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
+	if ((err = f75375_probe(client)) < 0)
 		goto exit_detach;
 
-	data->hwmon_dev = hwmon_device_register(&client->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		err = PTR_ERR(data->hwmon_dev);
-		goto exit_remove;
-	}
-
 	return 0;
 
-exit_remove:
-	sysfs_remove_group(&client->dev.kobj, &f75375_group);
 exit_detach:
 	i2c_detach_client(client);
 exit_free:
-	kfree(data);
+	kfree(client);
 exit:
 	return err;
 }
 
 static int __init sensors_f75375_init(void)
 {
-	return i2c_add_driver(&f75375_driver);
+	int status;
+	status = i2c_add_driver(&f75375_driver);
+	if (status)
+		return status;
+
+	status = i2c_add_driver(&f75375_legacy_driver);
+	if (status)
+		i2c_del_driver(&f75375_driver);
+
+	return status;
 }
 
 static void __exit sensors_f75375_exit(void)
 {
+	i2c_del_driver(&f75375_legacy_driver);
 	i2c_del_driver(&f75375_driver);
 }
 

+ 552 - 0
drivers/hwmon/i5k_amb.c

@@ -0,0 +1,552 @@
+/*
+ * A hwmon driver for the Intel 5000 series chipset FB-DIMM AMB
+ * temperature sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.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; 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#define DRVNAME "i5k_amb"
+
+#define I5K_REG_AMB_BASE_ADDR		0x48
+#define I5K_REG_AMB_LEN_ADDR		0x50
+#define I5K_REG_CHAN0_PRESENCE_ADDR	0x64
+#define I5K_REG_CHAN1_PRESENCE_ADDR	0x66
+
+#define AMB_REG_TEMP_MIN_ADDR		0x80
+#define AMB_REG_TEMP_MID_ADDR		0x81
+#define AMB_REG_TEMP_MAX_ADDR		0x82
+#define AMB_REG_TEMP_STATUS_ADDR	0x84
+#define AMB_REG_TEMP_ADDR		0x85
+
+#define AMB_CONFIG_SIZE			2048
+#define AMB_FUNC_3_OFFSET		768
+
+static unsigned long amb_reg_temp_status(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_STATUS_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_min(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MIN_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_mid(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MID_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_max(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MAX_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp(unsigned int amb)
+{
+	return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_ADDR +
+	       AMB_CONFIG_SIZE * amb;
+}
+
+#define MAX_MEM_CHANNELS		4
+#define MAX_AMBS_PER_CHANNEL		16
+#define MAX_AMBS			(MAX_MEM_CHANNELS * \
+					 MAX_AMBS_PER_CHANNEL)
+/*
+ * Ugly hack: For some reason the highest bit is set if there
+ * are _any_ DIMMs in the channel.  Attempting to read from
+ * this "high-order" AMB results in a memory bus error, so
+ * for now we'll just ignore that top bit, even though that
+ * might prevent us from seeing the 16th DIMM in the channel.
+ */
+#define REAL_MAX_AMBS_PER_CHANNEL	15
+#define KNOBS_PER_AMB			5
+
+static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit)
+{
+	return byte_num * MAX_AMBS_PER_CHANNEL + bit;
+}
+
+#define AMB_SYSFS_NAME_LEN		16
+struct i5k_device_attribute {
+	struct sensor_device_attribute s_attr;
+	char name[AMB_SYSFS_NAME_LEN];
+};
+
+struct i5k_amb_data {
+	struct device *hwmon_dev;
+
+	unsigned long amb_base;
+	unsigned long amb_len;
+	u16 amb_present[MAX_MEM_CHANNELS];
+	void __iomem *amb_mmio;
+	struct i5k_device_attribute *attrs;
+	unsigned int num_attrs;
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	return sprintf(buf, "%s\n", DRVNAME);
+}
+
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct platform_device *amb_pdev;
+
+static u8 amb_read_byte(struct i5k_amb_data *data, unsigned long offset)
+{
+	return ioread8(data->amb_mmio + offset);
+}
+
+static void amb_write_byte(struct i5k_amb_data *data, unsigned long offset,
+			   u8 val)
+{
+	iowrite8(val, data->amb_mmio + offset);
+}
+
+static ssize_t show_amb_alarm(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+
+	if (!(amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x20) &&
+	     (amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x8))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t store_amb_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 i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_min(attr->index), temp);
+	return count;
+}
+
+static ssize_t store_amb_mid(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf,
+			     size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_mid(attr->index), temp);
+	return count;
+}
+
+static ssize_t store_amb_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 i5k_amb_data *data = dev_get_drvdata(dev);
+	unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+	if (temp > 255)
+		temp = 255;
+
+	amb_write_byte(data, amb_reg_temp_max(attr->index), temp);
+	return count;
+}
+
+static ssize_t show_amb_min(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_min(attr->index)));
+}
+
+static ssize_t show_amb_mid(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_mid(attr->index)));
+}
+
+static ssize_t show_amb_max(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp_max(attr->index)));
+}
+
+static ssize_t show_amb_temp(struct device *dev,
+			     struct device_attribute *devattr,
+			     char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i5k_amb_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n",
+		500 * amb_read_byte(data, amb_reg_temp(attr->index)));
+}
+
+static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
+{
+	int i, j, k, d = 0;
+	u16 c;
+	int res = 0;
+	int num_ambs = 0;
+	struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+	/* Count the number of AMBs found */
+	/* ignore the high-order bit, see "Ugly hack" comment above */
+	for (i = 0; i < MAX_MEM_CHANNELS; i++)
+		num_ambs += hweight16(data->amb_present[i] & 0x7fff);
+
+	/* Set up sysfs stuff */
+	data->attrs = kzalloc(sizeof(*data->attrs) * num_ambs * KNOBS_PER_AMB,
+				GFP_KERNEL);
+	if (!data->attrs)
+		return -ENOMEM;
+	data->num_attrs = 0;
+
+	for (i = 0; i < MAX_MEM_CHANNELS; i++) {
+		c = data->amb_present[i];
+		for (j = 0; j < REAL_MAX_AMBS_PER_CHANNEL; j++, c >>= 1) {
+			struct i5k_device_attribute *iattr;
+
+			k = amb_num_from_reg(i, j);
+			if (!(c & 0x1))
+				continue;
+			d++;
+
+			/* Temperature sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_input", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_temp;
+			iattr->s_attr.index = k;
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature min sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_min", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_min;
+			iattr->s_attr.dev_attr.store = store_amb_min;
+			iattr->s_attr.index = k;
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature mid sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_mid", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_mid;
+			iattr->s_attr.dev_attr.store = store_amb_mid;
+			iattr->s_attr.index = k;
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature max sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_max", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_max;
+			iattr->s_attr.dev_attr.store = store_amb_max;
+			iattr->s_attr.index = k;
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+
+			/* Temperature alarm sysfs knob */
+			iattr = data->attrs + data->num_attrs;
+			snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+				 "temp%d_alarm", d);
+			iattr->s_attr.dev_attr.attr.name = iattr->name;
+			iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+			iattr->s_attr.dev_attr.show = show_amb_alarm;
+			iattr->s_attr.index = k;
+			res = device_create_file(&pdev->dev,
+						 &iattr->s_attr.dev_attr);
+			if (res)
+				goto exit_remove;
+			data->num_attrs++;
+		}
+	}
+
+	res = device_create_file(&pdev->dev, &dev_attr_name);
+	if (res)
+		goto exit_remove;
+
+	data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		res = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return res;
+
+exit_remove:
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	for (i = 0; i < data->num_attrs; i++)
+		device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+	kfree(data->attrs);
+
+	return res;
+}
+
+static int __devinit i5k_amb_add(void)
+{
+	int res = -ENODEV;
+
+	/* only ever going to be one of these */
+	amb_pdev = platform_device_alloc(DRVNAME, 0);
+	if (!amb_pdev)
+		return -ENOMEM;
+
+	res = platform_device_add(amb_pdev);
+	if (res)
+		goto err;
+	return 0;
+
+err:
+	platform_device_put(amb_pdev);
+	return res;
+}
+
+static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
+{
+	struct pci_dev *pcidev;
+	u32 val32;
+	int res = -ENODEV;
+
+	/* Find AMB register memory space */
+	pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_5000_ERR,
+				NULL);
+	if (!pcidev)
+		return -ENODEV;
+
+	if (pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32))
+		goto out;
+	data->amb_base = val32;
+
+	if (pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32))
+		goto out;
+	data->amb_len = val32;
+
+	/* Is it big enough? */
+	if (data->amb_len < AMB_CONFIG_SIZE * MAX_AMBS) {
+		dev_err(&pcidev->dev, "AMB region too small!\n");
+		goto out;
+	}
+
+	res = 0;
+out:
+	pci_dev_put(pcidev);
+	return res;
+}
+
+static int __devinit i5k_channel_probe(u16 *amb_present, unsigned long dev_id)
+{
+	struct pci_dev *pcidev;
+	u16 val16;
+	int res = -ENODEV;
+
+	/* Copy the DIMM presence map for these two channels */
+	pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
+	if (!pcidev)
+		return -ENODEV;
+
+	if (pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16))
+		goto out;
+	amb_present[0] = val16;
+
+	if (pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16))
+		goto out;
+	amb_present[1] = val16;
+
+	res = 0;
+
+out:
+	pci_dev_put(pcidev);
+	return res;
+}
+
+static int __devinit i5k_amb_probe(struct platform_device *pdev)
+{
+	struct i5k_amb_data *data;
+	struct resource *reso;
+	int res = -ENODEV;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* Figure out where the AMB registers live */
+	res = i5k_find_amb_registers(data);
+	if (res)
+		goto err;
+
+	/* Copy the DIMM presence map for the first two channels */
+	res = i5k_channel_probe(&data->amb_present[0],
+				PCI_DEVICE_ID_INTEL_5000_FBD0);
+	if (res)
+		goto err;
+
+	/* Copy the DIMM presence map for the optional second two channels */
+	i5k_channel_probe(&data->amb_present[2],
+			  PCI_DEVICE_ID_INTEL_5000_FBD1);
+
+	/* Set up resource regions */
+	reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
+	if (!reso) {
+		res = -EBUSY;
+		goto err;
+	}
+
+	data->amb_mmio = ioremap_nocache(data->amb_base, data->amb_len);
+	if (!data->amb_mmio) {
+		res = -EBUSY;
+		goto err_map_failed;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	res = i5k_amb_hwmon_init(pdev);
+	if (res)
+		goto err_init_failed;
+
+	return res;
+
+err_init_failed:
+	iounmap(data->amb_mmio);
+	platform_set_drvdata(pdev, NULL);
+err_map_failed:
+	release_mem_region(data->amb_base, data->amb_len);
+err:
+	kfree(data);
+	return res;
+}
+
+static int __devexit i5k_amb_remove(struct platform_device *pdev)
+{
+	int i;
+	struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	for (i = 0; i < data->num_attrs; i++)
+		device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+	kfree(data->attrs);
+	iounmap(data->amb_mmio);
+	release_mem_region(data->amb_base, data->amb_len);
+	platform_set_drvdata(pdev, NULL);
+	kfree(data);
+	return 0;
+}
+
+static struct platform_driver i5k_amb_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRVNAME,
+	},
+	.probe = i5k_amb_probe,
+	.remove = __devexit_p(i5k_amb_remove),
+};
+
+static int __init i5k_amb_init(void)
+{
+	int res;
+
+	res = platform_driver_register(&i5k_amb_driver);
+	if (res)
+		return res;
+
+	res = i5k_amb_add();
+	if (res)
+		platform_driver_unregister(&i5k_amb_driver);
+
+	return res;
+}
+
+static void __exit i5k_amb_exit(void)
+{
+	platform_device_unregister(amb_pdev);
+	platform_driver_unregister(&i5k_amb_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(i5k_amb_init);
+module_exit(i5k_amb_exit);

+ 23 - 25
drivers/hwmon/ibmpex.c

@@ -140,10 +140,10 @@ static int ibmpex_send_message(struct ibmpex_bmc_data *data)
 
 	return 0;
 out1:
-	printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err);
+	dev_err(data->bmc_device, "request_settime=%x\n", err);
 	return err;
 out:
-	printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err);
+	dev_err(data->bmc_device, "validate_addr=%x\n", err);
 	return err;
 }
 
@@ -161,14 +161,14 @@ static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
 	data->sensor_major = data->rx_msg_data[0];
 	data->sensor_minor = data->rx_msg_data[1];
 
-	printk(KERN_INFO DRVNAME ": Found BMC with sensor interface "
-	       "v%d.%d %d-%02d-%02d on interface %d\n",
-	       data->sensor_major,
-	       data->sensor_minor,
-	       extract_value(data->rx_msg_data, 2),
-	       data->rx_msg_data[4],
-	       data->rx_msg_data[5],
-	       data->interface);
+	dev_info(data->bmc_device, "Found BMC with sensor interface "
+		 "v%d.%d %d-%02d-%02d on interface %d\n",
+		 data->sensor_major,
+		 data->sensor_minor,
+		 extract_value(data->rx_msg_data, 2),
+		 data->rx_msg_data[4],
+		 data->rx_msg_data[5],
+		 data->interface);
 
 	return 0;
 }
@@ -212,8 +212,8 @@ static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
 	wait_for_completion(&data->read_complete);
 
 	if (data->rx_result || data->rx_msg_len < 26) {
-		printk(KERN_ERR "Error reading sensor %d, please check.\n",
-		       sensor);
+		dev_err(data->bmc_device, "Error reading sensor %d.\n",
+			sensor);
 		return -ENOENT;
 	}
 
@@ -456,8 +456,7 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data) {
-		printk(KERN_ERR DRVNAME ": Insufficient memory for BMC "
-		       "interface %d.\n", data->interface);
+		dev_err(dev, "Insufficient memory for BMC interface.\n");
 		return;
 	}
 
@@ -471,9 +470,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 	err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
 			       data, &data->user);
 	if (err < 0) {
-		printk(KERN_ERR DRVNAME ": Error, unable to register user with "
-		       "ipmi interface %d\n",
-		       data->interface);
+		dev_err(dev, "Unable to register user with IPMI "
+			"interface %d\n", data->interface);
 		goto out;
 	}
 
@@ -495,9 +493,9 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 	data->hwmon_dev = hwmon_device_register(data->bmc_device);
 
 	if (IS_ERR(data->hwmon_dev)) {
-		printk(KERN_ERR DRVNAME ": Error, unable to register hwmon "
-		       "class device for interface %d\n",
-		       data->interface);
+		dev_err(data->bmc_device, "Unable to register hwmon "
+			"device for IPMI interface %d\n",
+			data->interface);
 		goto out_user;
 	}
 
@@ -508,7 +506,7 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
 	/* Now go find all the sensors */
 	err = ibmpex_find_sensors(data);
 	if (err) {
-		printk(KERN_ERR "Error %d allocating memory\n", err);
+		dev_err(data->bmc_device, "Error %d finding sensors\n", err);
 		goto out_register;
 	}
 
@@ -561,10 +559,10 @@ static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
 	struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
 
 	if (msg->msgid != data->tx_msgid) {
-		printk(KERN_ERR "Received msgid (%02x) and transmitted "
-		       "msgid (%02x) mismatch!\n",
-		       (int)msg->msgid,
-		       (int)data->tx_msgid);
+		dev_err(data->bmc_device, "Mismatch between received msgid "
+			"(%02x) and transmitted msgid (%02x)!\n",
+			(int)msg->msgid,
+			(int)data->tx_msgid);
 		ipmi_free_recv_msg(msg);
 		return;
 	}

+ 6 - 5
drivers/hwmon/lm70.c

@@ -31,14 +31,15 @@
 #include <linux/err.h>
 #include <linux/sysfs.h>
 #include <linux/hwmon.h>
+#include <linux/mutex.h>
 #include <linux/spi/spi.h>
-#include <asm/semaphore.h>
+
 
 #define DRVNAME		"lm70"
 
 struct lm70 {
 	struct device *hwmon_dev;
-	struct semaphore sem;
+	struct mutex lock;
 };
 
 /* sysfs hook function */
@@ -51,7 +52,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
 	s16 raw=0;
 	struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
 
-	if (down_interruptible(&p_lm70->sem))
+	if (mutex_lock_interruptible(&p_lm70->lock))
 		return -ERESTARTSYS;
 
 	/*
@@ -83,7 +84,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
 	val = ((int)raw/32) * 250;
 	status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
 out:
-	up(&p_lm70->sem);
+	mutex_unlock(&p_lm70->lock);
 	return status;
 }
 
@@ -112,7 +113,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
 	if (!p_lm70)
 		return -ENOMEM;
 
-	init_MUTEX(&p_lm70->sem);
+	mutex_init(&p_lm70->lock);
 
 	/* sysfs hook */
 	p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);

+ 42 - 17
drivers/hwmon/sis5595.c

@@ -435,6 +435,22 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct sis5595_data *data = sis5595_update_device(dev);
+	int nr = to_sensor_dev_attr(da)->index;
+	return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
+
 static ssize_t show_name(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
@@ -447,22 +463,28 @@ static struct attribute *sis5595_attributes[] = {
 	&sensor_dev_attr_in0_input.dev_attr.attr,
 	&sensor_dev_attr_in0_min.dev_attr.attr,
 	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
 	&sensor_dev_attr_in1_input.dev_attr.attr,
 	&sensor_dev_attr_in1_min.dev_attr.attr,
 	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
 	&sensor_dev_attr_in2_input.dev_attr.attr,
 	&sensor_dev_attr_in2_min.dev_attr.attr,
 	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
 	&sensor_dev_attr_in3_input.dev_attr.attr,
 	&sensor_dev_attr_in3_min.dev_attr.attr,
 	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in3_alarm.dev_attr.attr,
 
 	&sensor_dev_attr_fan1_input.dev_attr.attr,
 	&sensor_dev_attr_fan1_min.dev_attr.attr,
 	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
 	&sensor_dev_attr_fan2_input.dev_attr.attr,
 	&sensor_dev_attr_fan2_min.dev_attr.attr,
 	&sensor_dev_attr_fan2_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
 
 	&dev_attr_alarms.attr,
 	&dev_attr_name.attr,
@@ -473,19 +495,28 @@ static const struct attribute_group sis5595_group = {
 	.attrs = sis5595_attributes,
 };
 
-static struct attribute *sis5595_attributes_opt[] = {
+static struct attribute *sis5595_attributes_in4[] = {
 	&sensor_dev_attr_in4_input.dev_attr.attr,
 	&sensor_dev_attr_in4_min.dev_attr.attr,
 	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in4_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group sis5595_group_in4 = {
+	.attrs = sis5595_attributes_in4,
+};
 
+static struct attribute *sis5595_attributes_temp1[] = {
 	&dev_attr_temp1_input.attr,
 	&dev_attr_temp1_max.attr,
 	&dev_attr_temp1_max_hyst.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
 	NULL
 };
 
-static const struct attribute_group sis5595_group_opt = {
-	.attrs = sis5595_attributes_opt,
+static const struct attribute_group sis5595_group_temp1 = {
+	.attrs = sis5595_attributes_temp1,
 };
  
 /* This is called when the module is loaded */
@@ -540,20 +571,12 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
 	if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
 		goto exit_free;
 	if (data->maxins == 4) {
-		if ((err = device_create_file(&pdev->dev,
-					&sensor_dev_attr_in4_input.dev_attr))
-		 || (err = device_create_file(&pdev->dev,
-					&sensor_dev_attr_in4_min.dev_attr))
-		 || (err = device_create_file(&pdev->dev,
-					&sensor_dev_attr_in4_max.dev_attr)))
+		if ((err = sysfs_create_group(&pdev->dev.kobj,
+					      &sis5595_group_in4)))
 			goto exit_remove_files;
 	} else {
-		if ((err = device_create_file(&pdev->dev,
-					      &dev_attr_temp1_input))
-		 || (err = device_create_file(&pdev->dev,
-					      &dev_attr_temp1_max))
-		 || (err = device_create_file(&pdev->dev,
-					      &dev_attr_temp1_max_hyst)))
+		if ((err = sysfs_create_group(&pdev->dev.kobj,
+					      &sis5595_group_temp1)))
 			goto exit_remove_files;
 	}
 
@@ -567,7 +590,8 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
 
 exit_remove_files:
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
-	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
 exit_free:
 	kfree(data);
 exit_release:
@@ -582,7 +606,8 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
-	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
 
 	release_region(data->addr, SIS5595_EXTENT);
 	platform_set_drvdata(pdev, NULL);

+ 57 - 98
drivers/hwmon/w83627hf.c

@@ -170,20 +170,16 @@ superio_exit(void)
 #define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \
 					   (0x550 + (nr) - 7))
 
-#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
-#define W83781D_REG_FAN(nr) (0x27 + (nr))
-
-#define W83781D_REG_TEMP2_CONFIG 0x152
-#define W83781D_REG_TEMP3_CONFIG 0x252
-#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
-					((nr == 2) ? (0x0150) : \
-					             (0x27)))
-#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \
-					((nr == 2) ? (0x153) : \
-					             (0x3A)))
-#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \
-					((nr == 2) ? (0x155) : \
-					             (0x39)))
+/* nr:0-2 for fans:1-3 */
+#define W83627HF_REG_FAN_MIN(nr)	(0x3b + (nr))
+#define W83627HF_REG_FAN(nr)		(0x28 + (nr))
+
+#define W83627HF_REG_TEMP2_CONFIG 0x152
+#define W83627HF_REG_TEMP3_CONFIG 0x252
+/* these are zero-based, unlike config constants above */
+static const u16 w83627hf_reg_temp[]		= { 0x27, 0x150, 0x250 };
+static const u16 w83627hf_reg_temp_hyst[]	= { 0x3A, 0x153, 0x253 };
+static const u16 w83627hf_reg_temp_over[]	= { 0x39, 0x155, 0x255 };
 
 #define W83781D_REG_BANK 0x4E
 
@@ -360,12 +356,9 @@ struct w83627hf_data {
 	u8 in_min[9];		/* Register value */
 	u8 fan[3];		/* Register value */
 	u8 fan_min[3];		/* Register value */
-	u8 temp;
-	u8 temp_max;		/* Register value */
-	u8 temp_max_hyst;	/* Register value */
-	u16 temp_add[2];	/* Register value */
-	u16 temp_max_add[2];	/* Register value */
-	u16 temp_max_hyst_add[2]; /* Register value */
+	u16 temp[3];		/* Register value */
+	u16 temp_max[3];	/* Register value */
+	u16 temp_max_hyst[3];	/* Register value */
 	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 vid;			/* Register encoding, combined */
 	u32 alarms;		/* Register encoding, combined */
@@ -590,7 +583,7 @@ store_fan_min(struct device *dev, struct device_attribute *devattr,
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1),
+	w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr),
 			     data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
@@ -611,12 +604,10 @@ show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
 {
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = w83627hf_update_device(dev);
-	if (nr >= 2) {	/* TEMP2 and TEMP3 */
-		return sprintf(buf, "%ld\n",
-			(long)LM75_TEMP_FROM_REG(data->temp_add[nr-2]));
-	} else {	/* TEMP1 */
-		return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp));
-	}
+
+	u16 tmp = data->temp[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
 }
 
 static ssize_t
@@ -625,13 +616,10 @@ show_temp_max(struct device *dev, struct device_attribute *devattr,
 {
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = w83627hf_update_device(dev);
-	if (nr >= 2) {	/* TEMP2 and TEMP3 */
-		return sprintf(buf, "%ld\n",
-			(long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2]));
-	} else {	/* TEMP1 */
-		return sprintf(buf, "%ld\n",
-			(long)TEMP_FROM_REG(data->temp_max));
-	}
+
+	u16 tmp = data->temp_max[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
 }
 
 static ssize_t
@@ -640,13 +628,10 @@ show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
 {
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = w83627hf_update_device(dev);
-	if (nr >= 2) {	/* TEMP2 and TEMP3 */
-		return sprintf(buf, "%ld\n",
-			(long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2]));
-	} else {	/* TEMP1 */
-		return sprintf(buf, "%ld\n",
-			(long)TEMP_FROM_REG(data->temp_max_hyst));
-	}
+
+	u16 tmp = data->temp_max_hyst[nr];
+	return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+					  : (long) TEMP_FROM_REG(tmp));
 }
 
 static ssize_t
@@ -656,18 +641,11 @@ store_temp_max(struct device *dev, struct device_attribute *devattr,
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
+	u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
 
 	mutex_lock(&data->update_lock);
-
-	if (nr >= 2) {	/* TEMP2 and TEMP3 */
-		data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val);
-		w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
-				data->temp_max_add[nr-2]);
-	} else {	/* TEMP1 */
-		data->temp_max = TEMP_TO_REG(val);
-		w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr),
-			data->temp_max);
-	}
+	data->temp_max[nr] = tmp;
+	w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -679,29 +657,22 @@ store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
+	u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
 
 	mutex_lock(&data->update_lock);
-
-	if (nr >= 2) {	/* TEMP2 and TEMP3 */
-		data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val);
-		w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
-				data->temp_max_hyst_add[nr-2]);
-	} else {	/* TEMP1 */
-		data->temp_max_hyst = TEMP_TO_REG(val);
-		w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr),
-			data->temp_max_hyst);
-	}
+	data->temp_max_hyst[nr] = tmp;
+	w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 #define sysfs_temp_decl(offset) \
 static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
-			  show_temp, NULL, offset);			\
+			  show_temp, NULL, offset - 1);			\
 static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR,	 	\
-			  show_temp_max, store_temp_max, offset);	\
+			  show_temp_max, store_temp_max, offset - 1);	\
 static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR,	\
-			  show_temp_max_hyst, store_temp_max_hyst, offset);
+			  show_temp_max_hyst, store_temp_max_hyst, offset - 1);
 
 sysfs_temp_decl(1);
 sysfs_temp_decl(2);
@@ -844,7 +815,7 @@ store_fan_div(struct device *dev, struct device_attribute *devattr,
 
 	/* Restore fan_min */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -1170,7 +1141,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	struct w83627hf_sio_data *sio_data = dev->platform_data;
 	struct w83627hf_data *data;
 	struct resource *res;
-	int err;
+	int err, i;
 
 	static const char *names[] = {
 		"w83627hf",
@@ -1204,9 +1175,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	w83627hf_init_device(pdev);
 
 	/* A few vars need to be filled upon startup */
-	data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
-	data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
-	data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
+	for (i = 0; i <= 2; i++)
+		data->fan_min[i] = w83627hf_read_value(
+					data, W83627HF_REG_FAN_MIN(i));
 	w83627hf_update_fan_div(data);
 
 	/* Register common device attributes */
@@ -1514,23 +1485,23 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
 
 	if(init) {
 		/* Enable temp2 */
-		tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
+		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
 		if (tmp & 0x01) {
 			dev_warn(&pdev->dev, "Enabling temp2, readings "
 				 "might not make sense\n");
-			w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
+			w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
 				tmp & 0xfe);
 		}
 
 		/* Enable temp3 */
 		if (type != w83697hf) {
 			tmp = w83627hf_read_value(data,
-				W83781D_REG_TEMP3_CONFIG);
+				W83627HF_REG_TEMP3_CONFIG);
 			if (tmp & 0x01) {
 				dev_warn(&pdev->dev, "Enabling temp3, "
 					 "readings might not make sense\n");
 				w83627hf_write_value(data,
-					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+					W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
 			}
 		}
 	}
@@ -1563,7 +1534,7 @@ static void w83627hf_update_fan_div(struct w83627hf_data *data)
 static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
-	int i;
+	int i, num_temps = (data->type == w83697hf) ? 2 : 3;
 
 	mutex_lock(&data->update_lock);
 
@@ -1584,12 +1555,12 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 			    w83627hf_read_value(data,
 					       W83781D_REG_IN_MAX(i));
 		}
-		for (i = 1; i <= 3; i++) {
-			data->fan[i - 1] =
-			    w83627hf_read_value(data, W83781D_REG_FAN(i));
-			data->fan_min[i - 1] =
+		for (i = 0; i <= 2; i++) {
+			data->fan[i] =
+			    w83627hf_read_value(data, W83627HF_REG_FAN(i));
+			data->fan_min[i] =
 			    w83627hf_read_value(data,
-					       W83781D_REG_FAN_MIN(i));
+					       W83627HF_REG_FAN_MIN(i));
 		}
 		for (i = 0; i <= 2; i++) {
 			u8 tmp = w83627hf_read_value(data,
@@ -1616,25 +1587,13 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 					break;
 			}
 		}
-
-		data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
-		data->temp_max =
-		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
-		data->temp_max_hyst =
-		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
-		data->temp_add[0] =
-		    w83627hf_read_value(data, W83781D_REG_TEMP(2));
-		data->temp_max_add[0] =
-		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
-		data->temp_max_hyst_add[0] =
-		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
-		if (data->type != w83697hf) {
-			data->temp_add[1] =
-			  w83627hf_read_value(data, W83781D_REG_TEMP(3));
-			data->temp_max_add[1] =
-			  w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
-			data->temp_max_hyst_add[1] =
-			  w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
+		for (i = 0; i < num_temps; i++) {
+			data->temp[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp[i]);
+			data->temp_max[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp_over[i]);
+			data->temp_max_hyst[i] = w83627hf_read_value(
+						data, w83627hf_reg_temp_hyst[i]);
 		}
 
 		w83627hf_update_fan_div(data);

+ 2 - 1
drivers/hwmon/w83781d.c

@@ -1122,12 +1122,13 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
 				&sensor_dev_attr_temp3_beep.dev_attr)))
 			return err;
 
-		if (kind != w83781d)
+		if (kind != w83781d) {
 			err = sysfs_chmod_file(&dev->kobj,
 				&sensor_dev_attr_temp3_alarm.dev_attr.attr,
 				S_IRUGO | S_IWUSR);
 			if (err)
 				return err;
+		}
 	}
 
 	if (kind != w83781d && kind != as99127f) {

+ 21 - 0
include/linux/f75375s.h

@@ -0,0 +1,21 @@
+/*
+ * f75375s.h - platform data structure for f75375s sensor
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007, Riku Voipio <riku.voipio@iki.fi>
+ */
+
+#ifndef __LINUX_F75375S_H
+#define __LINUX_F75375S_H
+
+/* We want to set fans spinning on systems where there is no
+ * BIOS to do that for us */
+struct f75375s_platform_data {
+	u8 pwm[2];
+	u8 pwm_enable[2];
+};
+
+#endif /* __LINUX_F75375S_H */

+ 3 - 0
include/linux/pci_ids.h

@@ -2276,6 +2276,9 @@
 #define PCI_DEVICE_ID_INTEL_82915G_IG	0x2582
 #define PCI_DEVICE_ID_INTEL_82915GM_HB	0x2590
 #define PCI_DEVICE_ID_INTEL_82915GM_IG	0x2592
+#define PCI_DEVICE_ID_INTEL_5000_ERR	0x25F0
+#define PCI_DEVICE_ID_INTEL_5000_FBD0	0x25F5
+#define PCI_DEVICE_ID_INTEL_5000_FBD1	0x25F6
 #define PCI_DEVICE_ID_INTEL_82945G_HB	0x2770
 #define PCI_DEVICE_ID_INTEL_82945G_IG	0x2772
 #define PCI_DEVICE_ID_INTEL_3000_HB	0x2778