aboutsummaryrefslogtreecommitdiffstats
path: root/i2c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-06-06 16:25:32 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-06 16:25:32 -0700
commitb2267928115c563206ff006eb83e7935b7565eec (patch)
tree9bde67c65534c1711480385e9acaf67630be1ed9 /i2c
parent24422233277d7b2b940fa93e7374d881063a6cff (diff)
downloadpatches-b2267928115c563206ff006eb83e7935b7565eec.tar.gz
i2c patches and remove kevent patch
Diffstat (limited to 'i2c')
-rw-r--r--i2c/hwmon-abituguru-fixes.patch416
-rw-r--r--i2c/hwmon-abituguru-new-driver.patch1843
-rw-r--r--i2c/hwmon-abituguru-nofans-detect-fix.patch39
-rw-r--r--i2c/hwmon-hdaps-typo.patch30
-rw-r--r--i2c/hwmon-maintenance-update.patch47
-rw-r--r--i2c/hwmon-sysfs-interface-update-1.patch379
-rw-r--r--i2c/hwmon-sysfs-interface-update-2.patch138
-rw-r--r--i2c/hwmon-w83792d-add-data-lock.patch194
-rw-r--r--i2c/hwmon-w83792d-pwm-set-fix.patch173
-rw-r--r--i2c/i2c-Kconfig-suggest-N-for-rare-devices.patch88
-rw-r--r--i2c/i2c-opencores-new-driver.patch479
11 files changed, 3826 insertions, 0 deletions
diff --git a/i2c/hwmon-abituguru-fixes.patch b/i2c/hwmon-abituguru-fixes.patch
new file mode 100644
index 0000000000000..06680ba23b7f2
--- /dev/null
+++ b/i2c/hwmon-abituguru-fixes.patch
@@ -0,0 +1,416 @@
+From khali@linux-fr.org Sun Jun 4 11:23:04 2006
+Date: Sun, 4 Jun 2006 20:23:01 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: abituguru: Review fixes
+Message-Id: <20060604202301.df24f89f.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-abituguru-fixes.patch
+
+From: Hans de Goede <j.w.r.degoede@hhs.nl>
+
+Fixes to the Abit uGuru driver as requested in review by Jean Delvare:
+ - exactly calculate the sysfs_names array length using macro
+ - use snprintf when generating names to double check that the sysfs_names
+ array does not overflow.
+ - use ARRAY_SIZE and / or defines to determine number of loops in for loops
+ instead of using hardcoded values.
+ - In abituguru_probe(), refactor the error path leaving a single call to kfree
+
+Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/abituguru.c | 195 +++++++++++++++++++++++++---------------------
+ 1 file changed, 110 insertions(+), 85 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/abituguru.c
++++ gregkh-2.6/drivers/hwmon/abituguru.c
+@@ -36,6 +36,10 @@
+ #define ABIT_UGURU_SENSOR_BANK1 0x21 /* 16x volt and temp */
+ #define ABIT_UGURU_FAN_PWM 0x24 /* 3x 5 bytes */
+ #define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */
++/* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */
++#define ABIT_UGURU_MAX_BANK1_SENSORS 16
++/* Warning if you increase one of the 2 MAX defines below to 10 or higher you
++ should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! */
+ /* max nr of sensors in bank2, currently mb's with max 6 fans are known */
+ #define ABIT_UGURU_MAX_BANK2_SENSORS 6
+ /* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
+@@ -74,10 +78,33 @@
+ /* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
+ #define ABIT_UGURU_MAX_RETRIES 3
+ #define ABIT_UGURU_RETRY_DELAY (HZ/5)
+-/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is a error */
++/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is an error */
+ #define ABIT_UGURU_MAX_TIMEOUTS 2
++/* utility macros */
++#define ABIT_UGURU_NAME "abituguru"
++#define ABIT_UGURU_DEBUG(level, format, arg...) \
++ if (level <= verbose) \
++ printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
++/* Macros to help calculate the sysfs_names array length */
++/* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
++ in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 */
++#define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14)
++/* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0,
++ temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 */
++#define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16)
++/* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0,
++ fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 */
++#define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14)
++/* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0,
++ pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 */
++#define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22)
++/* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */
++#define ABITUGURU_SYSFS_NAMES_LENGTH ( \
++ ABIT_UGURU_MAX_BANK1_SENSORS * ABITUGURU_IN_NAMES_LENGTH + \
++ ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \
++ ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH)
+
+-/* All the variables below are named identical to the oguru and oguru2 programs
++/* All the macros below are named identical to the oguru and oguru2 programs
+ reverse engineered by Olle Sandberg, hence the names might not be 100%
+ logical. I could come up with better names, but I prefer keeping the names
+ identical so that this driver can be compared with his work more easily. */
+@@ -93,11 +120,6 @@
+ #define ABIT_UGURU_STATUS_READ 0x01 /* Ready to be read */
+ #define ABIT_UGURU_STATUS_INPUT 0x08 /* More input */
+ #define ABIT_UGURU_STATUS_READY 0x09 /* Ready to be written */
+-/* utility macros */
+-#define ABIT_UGURU_NAME "abituguru"
+-#define ABIT_UGURU_DEBUG(level, format, arg...) \
+- if (level <= verbose) \
+- printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
+
+ /* Constants */
+ /* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
+@@ -156,24 +178,23 @@ struct abituguru_data {
+ of a sensor is a volt or a temp sensor, for bank2 and the pwms its
+ easier todo things the same way. For in sensors we have 9 (temp 7)
+ sysfs entries per sensor, for bank2 and pwms 6. */
+- struct sensor_device_attribute_2 sysfs_attr[16 * 9 +
++ struct sensor_device_attribute_2 sysfs_attr[
++ ABIT_UGURU_MAX_BANK1_SENSORS * 9 +
+ ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
+- /* Buffer to store the dynamically generated sysfs names, we need 2120
+- bytes for bank1 (worst case scenario of 16 in sensors), 444 bytes
+- for fan1-6 and 738 bytes for pwm1-6 + some room to spare in case I
+- miscounted :) */
+- char bank1_names[3400];
++ /* Buffer to store the dynamically generated sysfs names */
++ char sysfs_names[ABITUGURU_SYSFS_NAMES_LENGTH];
+
+ /* Bank 1 data */
+- u8 bank1_sensors[2]; /* number of [0] in, [1] temp sensors */
+- u8 bank1_address[2][16];/* addresses of [0] in, [1] temp sensors */
+- u8 bank1_value[16];
+- /* This array holds 16 x 3 entries for all the bank 1 sensor settings
++ /* number of and addresses of [0] in, [1] temp sensors */
++ u8 bank1_sensors[2];
++ u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS];
++ u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS];
++ /* This array holds 3 entries per sensor for the bank 1 sensor settings
+ (flags, min, max for voltage / flags, warn, shutdown for temp). */
+- u8 bank1_settings[16][3];
++ u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3];
+ /* Maximum value for each sensor used for scaling in mV/millidegrees
+ Celsius. */
+- int bank1_max_value[16];
++ int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS];
+
+ /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
+ u8 bank2_sensors; /* actual number of bank2 sensors found */
+@@ -379,7 +400,7 @@ abituguru_detect_bank1_sensor_type(struc
+ /* First read the sensor and the current settings */
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
+ 1, ABIT_UGURU_MAX_RETRIES) != 1)
+- return -EIO;
++ return -ENODEV;
+
+ /* Test val is sane / usable for sensor type detection. */
+ if ((val < 10u) || (val > 240u)) {
+@@ -401,7 +422,7 @@ abituguru_detect_bank1_sensor_type(struc
+ buf[2] = 250;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ buf, 3) != 3)
+- return -EIO;
++ return -ENODEV;
+ /* Now we need 20 ms to give the uguru time to read the sensors
+ and raise a voltage alarm */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+@@ -409,19 +430,19 @@ abituguru_detect_bank1_sensor_type(struc
+ /* Check for alarm and check the alarm is a volt low alarm. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+- return -EIO;
++ return -ENODEV;
+ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+ sensor_addr, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+- return -EIO;
++ return -ENODEV;
+ if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+ /* Restore original settings */
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+ sensor_addr,
+ data->bank1_settings[sensor_addr],
+ 3) != 3)
+- return -EIO;
++ return -ENODEV;
+ ABIT_UGURU_DEBUG(2, " found volt sensor\n");
+ return ABIT_UGURU_IN_SENSOR;
+ } else
+@@ -439,7 +460,7 @@ abituguru_detect_bank1_sensor_type(struc
+ buf[2] = 10;
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ buf, 3) != 3)
+- return -EIO;
++ return -ENODEV;
+ /* Now we need 50 ms to give the uguru time to read the sensors
+ and raise a temp alarm */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+@@ -447,12 +468,12 @@ abituguru_detect_bank1_sensor_type(struc
+ /* Check for alarm and check the alarm is a temp high alarm. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+- return -EIO;
++ return -ENODEV;
+ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+ sensor_addr, buf, 3,
+ ABIT_UGURU_MAX_RETRIES) != 3)
+- return -EIO;
++ return -ENODEV;
+ if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
+ ret = ABIT_UGURU_TEMP_SENSOR;
+ ABIT_UGURU_DEBUG(2, " found temp sensor\n");
+@@ -466,7 +487,7 @@ abituguru_detect_bank1_sensor_type(struc
+ /* Restore original settings */
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+ data->bank1_settings[sensor_addr], 3) != 3)
+- return -EIO;
++ return -ENODEV;
+
+ return ret;
+ }
+@@ -1061,21 +1082,21 @@ static const struct sensor_device_attrib
+ store_pwm_setting, 4, 0),
+ };
+
+-static const struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
++static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
+ SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+ };
+
+ static int __devinit abituguru_probe(struct platform_device *pdev)
+ {
+ struct abituguru_data *data;
+- int i, j, res;
++ int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+ char *sysfs_filename;
+- int sysfs_attr_i = 0;
+
+ /* El weirdo probe order, to keep the sysfs order identical to the
+ BIOS and window-appliction listing order. */
+- const u8 probe_order[16] = { 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E,
+- 0x02, 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
++ const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = {
++ 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
++ 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
+
+ if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL)))
+ return -ENOMEM;
+@@ -1092,24 +1113,18 @@ static int __devinit abituguru_probe(str
+ - testread / see if one really is there.
+ - make an in memory copy of all the uguru settings for future use. */
+ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+- data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) {
+- kfree(data);
+- return -ENODEV;
+- }
++ data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3)
++ goto abituguru_probe_error;
+
+- for (i = 0; i < 16; i++) {
++ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i,
+ &data->bank1_value[i], 1,
+- ABIT_UGURU_MAX_RETRIES) != 1) {
+- kfree(data);
+- return -ENODEV;
+- }
++ ABIT_UGURU_MAX_RETRIES) != 1)
++ goto abituguru_probe_error;
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i,
+ data->bank1_settings[i], 3,
+- ABIT_UGURU_MAX_RETRIES) != 3) {
+- kfree(data);
+- return -ENODEV;
+- }
++ ABIT_UGURU_MAX_RETRIES) != 3)
++ goto abituguru_probe_error;
+ }
+ /* Note: We don't know how many bank2 sensors / pwms there really are,
+ but in order to "detect" this we need to read the maximum amount
+@@ -1119,48 +1134,45 @@ static int __devinit abituguru_probe(str
+ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
+ &data->bank2_value[i], 1,
+- ABIT_UGURU_MAX_RETRIES) != 1) {
+- kfree(data);
+- return -ENODEV;
+- }
++ ABIT_UGURU_MAX_RETRIES) != 1)
++ goto abituguru_probe_error;
+ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i,
+ data->bank2_settings[i], 2,
+- ABIT_UGURU_MAX_RETRIES) != 2) {
+- kfree(data);
+- return -ENODEV;
+- }
++ ABIT_UGURU_MAX_RETRIES) != 2)
++ goto abituguru_probe_error;
+ }
+ for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+ if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i,
+ data->pwm_settings[i], 5,
+- ABIT_UGURU_MAX_RETRIES) != 5) {
+- kfree(data);
+- return -ENODEV;
+- }
++ ABIT_UGURU_MAX_RETRIES) != 5)
++ goto abituguru_probe_error;
+ }
+ data->last_updated = jiffies;
+
+ /* Detect sensor types and fill the sysfs attr for bank1 */
+- sysfs_filename = data->bank1_names;
+- for (i = 0; i < 16; i++) {
++ sysfs_attr_i = 0;
++ sysfs_filename = data->sysfs_names;
++ sysfs_names_free = ABITUGURU_SYSFS_NAMES_LENGTH;
++ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ res = abituguru_detect_bank1_sensor_type(data, probe_order[i]);
+- if (res < 0) {
+- kfree(data);
+- return -ENODEV;
+- }
++ if (res < 0)
++ goto abituguru_probe_error;
+ if (res == ABIT_UGURU_NC)
+ continue;
+
++ /* res 1 (temp) sensors have 7 sysfs entries, 0 (in) 9 */
+ for (j = 0; j < (res ? 7 : 9); j++) {
+- const char *name_templ = abituguru_sysfs_bank1_templ[
+- res][j].dev_attr.attr.name;
++ used = snprintf(sysfs_filename, sysfs_names_free,
++ abituguru_sysfs_bank1_templ[res][j].dev_attr.
++ attr.name, data->bank1_sensors[res] + res)
++ + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_bank1_templ[res][j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+- sysfs_filename += sprintf(sysfs_filename, name_templ,
+- data->bank1_sensors[res] + res) + 1;
+ data->sysfs_attr[sysfs_attr_i].index = probe_order[i];
++ sysfs_filename += used;
++ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ data->bank1_max_value[probe_order[i]] =
+@@ -1172,52 +1184,65 @@ static int __devinit abituguru_probe(str
+ /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */
+ abituguru_detect_no_bank2_sensors(data);
+ for (i = 0; i < data->bank2_sensors; i++) {
+- for (j = 0; j < 6; j++) {
+- const char *name_templ = abituguru_sysfs_fan_templ[j].
+- dev_attr.attr.name;
++ for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_fan_templ); j++) {
++ used = snprintf(sysfs_filename, sysfs_names_free,
++ abituguru_sysfs_fan_templ[j].dev_attr.attr.name,
++ i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_fan_templ[j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+- sysfs_filename += sprintf(sysfs_filename, name_templ,
+- i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i].index = i;
++ sysfs_filename += used;
++ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ }
+ /* Detect number of sensors and fill the sysfs attr for pwms */
+ abituguru_detect_no_pwms(data);
+ for (i = 0; i < data->pwms; i++) {
+- for (j = 0; j < 6; j++) {
+- const char *name_templ = abituguru_sysfs_pwm_templ[j].
+- dev_attr.attr.name;
++ for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_pwm_templ); j++) {
++ used = snprintf(sysfs_filename, sysfs_names_free,
++ abituguru_sysfs_pwm_templ[j].dev_attr.attr.name,
++ i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru_sysfs_pwm_templ[j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+- sysfs_filename += sprintf(sysfs_filename, name_templ,
+- i + 1) + 1;
+ data->sysfs_attr[sysfs_attr_i].index = i;
++ sysfs_filename += used;
++ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ }
+- /* Last add any "generic" entries to sysfs */
+- for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) {
+- data->sysfs_attr[sysfs_attr_i] = abituguru_sysfs_attr[i];
+- sysfs_attr_i++;
++ /* Fail safe check, this should never happen! */
++ if (sysfs_names_free < 0) {
++ printk(KERN_ERR ABIT_UGURU_NAME ": Fatal error ran out of "
++ "space for sysfs attr names. This should never "
++ "happen please report to the abituguru maintainer "
++ "(see MAINTAINERS)\n");
++ res = -ENAMETOOLONG;
++ goto abituguru_probe_error;
+ }
+ printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
+
+ /* Register sysfs hooks */
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+- kfree(data);
+- return PTR_ERR(data->class_dev);
++ res = PTR_ERR(data->class_dev);
++ goto abituguru_probe_error;
+ }
+ for (i = 0; i < sysfs_attr_i; i++)
+ device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
++ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
++ device_create_file(&pdev->dev,
++ &abituguru_sysfs_attr[i].dev_attr);
+
+ return 0;
++
++abituguru_probe_error:
++ kfree(data);
++ return res;
+ }
+
+ static int __devexit abituguru_remove(struct platform_device *pdev)
+@@ -1244,7 +1269,7 @@ static struct abituguru_data *abituguru_
+ if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+ data->alarms, 3, 0)) != 3)
+ goto LEAVE_UPDATE;
+- for (i = 0; i < 16; i++) {
++ for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) {
+ if ((err = abituguru_read(data,
+ ABIT_UGURU_SENSOR_BANK1, i,
+ &data->bank1_value[i], 1, 0)) != 1)
diff --git a/i2c/hwmon-abituguru-new-driver.patch b/i2c/hwmon-abituguru-new-driver.patch
new file mode 100644
index 0000000000000..8abb085abb2f3
--- /dev/null
+++ b/i2c/hwmon-abituguru-new-driver.patch
@@ -0,0 +1,1843 @@
+From khali@linux-fr.org Sun Jun 4 11:22:28 2006
+Date: Sun, 4 Jun 2006 20:22:24 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: abituguru: New hardware monitoring driver
+Message-Id: <20060604202224.b38707bd.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-abituguru-new-driver.patch
+
+From: Hans de Goede <j.w.r.degoede@hhs.nl>
+
+New hardware monitoring driver for the Abit uGuru
+
+Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/abituguru | 59 +
+ Documentation/hwmon/abituguru-datasheet | 312 +++++++
+ MAINTAINERS | 6
+ drivers/hwmon/Kconfig | 12
+ drivers/hwmon/Makefile | 1
+ drivers/hwmon/abituguru.c | 1391 ++++++++++++++++++++++++++++++++
+ 6 files changed, 1781 insertions(+)
+
+--- /dev/null
++++ gregkh-2.6/Documentation/hwmon/abituguru
+@@ -0,0 +1,59 @@
++Kernel driver abituguru
++=======================
++
++Supported chips:
++ * Abit uGuru (Hardware Monitor part only)
++ Prefix: 'abituguru'
++ Addresses scanned: ISA 0x0E0
++ Datasheet: Not available, this driver is based on reverse engineering.
++ A "Datasheet" has been written based on the reverse engineering it
++ should be available in the same dir as this file under the name
++ abituguru-datasheet.
++
++Authors:
++ Hans de Goede <j.w.r.degoede@hhs.nl>,
++ (Initial reverse engineering done by Olle Sandberg
++ <ollebull@gmail.com>)
++
++
++Module Parameters
++-----------------
++
++* force: bool Force detection. Note this parameter only causes the
++ detection to be skipped, if the uGuru can't be read
++ the module initialization (insmod) will still fail.
++* fan_sensors: int Tell the driver how many fan speed sensors there are
++ on your motherboard. Default: 0 (autodetect).
++* pwms: int Tell the driver how many fan speed controls (fan
++ pwms) your motherboard has. Default: 0 (autodetect).
++* verbose: int How verbose should the driver be? (0-3):
++ 0 normal output
++ 1 + verbose error reporting
++ 2 + sensors type probing info\n"
++ 3 + retryable error reporting
++ Default: 2 (the driver is still in the testing phase)
++
++Notice if you need any of the first three options above please insmod the
++driver with verbose set to 3 and mail me <j.w.r.degoede@hhs.nl> the output of:
++dmesg | grep abituguru
++
++
++Description
++-----------
++
++This driver supports the hardware monitoring features of the Abit uGuru chip
++found on Abit uGuru featuring motherboards (most modern Abit motherboards).
++
++The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
++claiming it is "a new microprocessor designed by the ABIT Engineers").
++Unfortunatly this doesn't help since the W83L950D is a generic
++microcontroller with a custom Abit application running on it.
++
++Despite Abit not releasing any information regarding the uGuru, Olle
++Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part
++of the uGuru. Without his work this driver would not have been possible.
++
++Known Issues
++------------
++
++The voltage and frequency control parts of the Abit uGuru are not supported.
+--- /dev/null
++++ gregkh-2.6/Documentation/hwmon/abituguru-datasheet
+@@ -0,0 +1,312 @@
++uGuru datasheet
++===============
++
++First of all, what I know about uGuru is no fact based on any help, hints or
++datasheet from Abit. The data I have got on uGuru have I assembled through
++my weak knowledge in "backwards engineering".
++And just for the record, you may have noticed uGuru isn't a chip developed by
++Abit, as they claim it to be. It's realy just an microprocessor (uC) created by
++Winbond (W83L950D). And no, reading the manual for this specific uC or
++mailing Windbond for help won't give any usefull data about uGuru, as it is
++the program inside the uC that is responding to calls.
++
++Olle Sandberg <ollebull@gmail.com>, 2005-05-25
++
++
++Original version by Olle Sandberg who did the heavy lifting of the initial
++reverse engineering. This version has been almost fully rewritten for clarity
++and extended with write support and info on more databanks, the write support
++is once again reverse engineered by Olle the additional databanks have been
++reverse engineered by me. I would like to express my thanks to Olle, this
++document and the Linux driver could not have been written without his efforts.
++
++Note: because of the lack of specs only the sensors part of the uGuru is
++described here and not the CPU / RAM / etc voltage & frequency control.
++
++Hans de Goede <j.w.r.degoede@hhs.nl>, 28-01-2006
++
++
++Detection
++=========
++
++As far as known the uGuru is always placed at and using the (ISA) I/O-ports
++0xE0 and 0xE4, so we don't have to scan any port-range, just check what the two
++ports are holding for detection. We will refer to 0xE0 as CMD (command-port)
++and 0xE4 as DATA because Abit refers to them with these names.
++
++If DATA holds 0x00 or 0x08 and CMD holds 0x00 or 0xAC an uGuru could be
++present. We have to check for two different values at data-port, because
++after a reboot uGuru will hold 0x00 here, but if the driver is removed and
++later on attached again data-port will hold 0x08, more about this later.
++
++After wider testing of the Linux kernel driver some variants of the uGuru have
++turned up which will hold 0x00 instead of 0xAC at the CMD port, thus we also
++have to test CMD for two different values. On these uGuru's DATA will initally
++hold 0x09 and will only hold 0x08 after reading CMD first, so CMD must be read
++first!
++
++To be really sure an uGuru is present a test read of one or more register
++sets should be done.
++
++
++Reading / Writing
++=================
++
++Addressing
++----------
++
++The uGuru has a number of different addressing levels. The first addressing
++level we will call banks. A bank holds data for one or more sensors. The data
++in a bank for a sensor is one or more bytes large.
++
++The number of bytes is fixed for a given bank, you should always read or write
++that many bytes, reading / writing more will fail, the results when writing
++less then the number of bytes for a given bank are undetermined.
++
++See below for all known bank addresses, numbers of sensors in that bank,
++number of bytes data per sensor and contents/meaning of those bytes.
++
++Although both this document and the kernel driver have kept the sensor
++terminoligy for the addressing within a bank this is not 100% correct, in
++bank 0x24 for example the addressing within the bank selects a PWM output not
++a sensor.
++
++Notice that some banks have both a read and a write address this is how the
++uGuru determines if a read from or a write to the bank is taking place, thus
++when reading you should always use the read address and when writing the
++write address. The write address is always one (1) more then the read address.
++
++
++uGuru ready
++-----------
++
++Before you can read from or write to the uGuru you must first put the uGuru
++in "ready" mode.
++
++To put the uGuru in ready mode first write 0x00 to DATA and then wait for DATA
++to hold 0x09, DATA should read 0x09 within 250 read cycles.
++
++Next CMD _must_ be read and should hold 0xAC, usually CMD will hold 0xAC the
++first read but sometimes it takes a while before CMD holds 0xAC and thus it
++has to be read a number of times (max 50).
++
++After reading CMD, DATA should hold 0x08 which means that the uGuru is ready
++for input. As above DATA will usually hold 0x08 the first read but not always.
++This step can be skipped, but it is undetermined what happens if the uGuru has
++not yet reported 0x08 at DATA and you proceed with writing a bank address.
++
++
++Sending bank and sensor addresses to the uGuru
++----------------------------------------------
++
++First the uGuru must be in "ready" mode as described above, DATA should hold
++0x08 indicating that the uGuru wants input, in this case the bank address.
++
++Next write the bank address to DATA. After the bank address has been written
++wait for to DATA to hold 0x08 again indicating that it wants / is ready for
++more input (max 250 reads).
++
++Once DATA holds 0x08 again write the sensor address to CMD.
++
++
++Reading
++-------
++
++First send the bank and sensor addresses as described above.
++Then for each byte of data you want to read wait for DATA to hold 0x01
++which indicates that the uGuru is ready to be read (max 250 reads) and once
++DATA holds 0x01 read the byte from CMD.
++
++Once all bytes have been read data will hold 0x09, but there is no reason to
++test for this. Notice that the number of bytes is bank address dependent see
++above and below.
++
++After completing a successfull read it is advised to put the uGuru back in
++ready mode, so that it is ready for the next read / write cycle. This way
++if your program / driver is unloaded and later loaded again the detection
++algorithm described above will still work.
++
++
++
++Writing
++-------
++
++First send the bank and sensor addresses as described above.
++Then for each byte of data you want to write wait for DATA to hold 0x00
++which indicates that the uGuru is ready to be written (max 250 reads) and
++once DATA holds 0x00 write the byte to CMD.
++
++Once all bytes have been written wait for DATA to hold 0x01 (max 250 reads)
++don't ask why this is the way it is.
++
++Once DATA holds 0x01 read CMD it should hold 0xAC now.
++
++After completing a successfull write it is advised to put the uGuru back in
++ready mode, so that it is ready for the next read / write cycle. This way
++if your program / driver is unloaded and later loaded again the detection
++algorithm described above will still work.
++
++
++Gotchas
++-------
++
++After wider testing of the Linux kernel driver some variants of the uGuru have
++turned up which do not hold 0x08 at DATA within 250 reads after writing the
++bank address. With these versions this happens quite frequent, using larger
++timeouts doesn't help, they just go offline for a second or 2, doing some
++internal callibration or whatever. Your code should be prepared to handle
++this and in case of no response in this specific case just goto sleep for a
++while and then retry.
++
++
++Address Map
++===========
++
++Bank 0x20 Alarms (R)
++--------------------
++This bank contains 0 sensors, iow the sensor address is ignored (but must be
++written) just use 0. Bank 0x20 contains 3 bytes:
++
++Byte 0:
++This byte holds the alarm flags for sensor 0-7 of Sensor Bank1, with bit 0
++corresponding to sensor 0, 1 to 1, etc.
++
++Byte 1:
++This byte holds the alarm flags for sensor 8-15 of Sensor Bank1, with bit 0
++corresponding to sensor 8, 1 to 9, etc.
++
++Byte 2:
++This byte holds the alarm flags for sensor 0-5 of Sensor Bank2, with bit 0
++corresponding to sensor 0, 1 to 1, etc.
++
++
++Bank 0x21 Sensor Bank1 Values / Readings (R)
++--------------------------------------------
++This bank contains 16 sensors, for each sensor it contains 1 byte.
++So far the following sensors are known to be available on all motherboards:
++Sensor 0 CPU temp
++Sensor 1 SYS temp
++Sensor 3 CPU core volt
++Sensor 4 DDR volt
++Sensor 10 DDR Vtt volt
++Sensor 15 PWM temp
++
++Byte 0:
++This byte holds the reading from the sensor. Sensors in Bank1 can be both
++volt and temp sensors, this is motherboard specific. The uGuru however does
++seem to know (be programmed with) what kindoff sensor is attached see Sensor
++Bank1 Settings description.
++
++Volt sensors use a linear scale, a reading 0 corresponds with 0 volt and a
++reading of 255 with 3494 mV. The sensors for higher voltages however are
++connected through a division circuit. The currently known division circuits
++in use result in ranges of: 0-4361mV, 0-6248mV or 0-14510mV. 3.3 volt sources
++use the 0-4361mV range, 5 volt the 0-6248mV and 12 volt the 0-14510mV .
++
++Temp sensors also use a linear scale, a reading of 0 corresponds with 0 degree
++Celsius and a reading of 255 with a reading of 255 degrees Celsius.
++
++
++Bank 0x22 Sensor Bank1 Settings (R)
++Bank 0x23 Sensor Bank1 Settings (W)
++-----------------------------------
++
++This bank contains 16 sensors, for each sensor it contains 3 bytes. Each
++set of 3 bytes contains the settings for the sensor with the same sensor
++address in Bank 0x21 .
++
++Byte 0:
++Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
++Bit 0: Give an alarm if measured temp is over the warning threshold (RW) *
++Bit 1: Give an alarm if measured volt is over the max threshold (RW) **
++Bit 2: Give an alarm if measured volt is under the min threshold (RW) **
++Bit 3: Beep if alarm (RW)
++Bit 4: 1 if alarm cause measured temp is over the warning threshold (R)
++Bit 5: 1 if alarm cause measured volt is over the max threshold (R)
++Bit 6: 1 if alarm cause measured volt is under the min threshold (R)
++Bit 7: Volt sensor: Shutdown if alarm persist for more then 4 seconds (RW)
++ Temp sensor: Shutdown if temp is over the shutdown threshold (RW)
++
++* This bit is only honored/used by the uGuru if a temp sensor is connected
++** This bit is only honored/used by the uGuru if a volt sensor is connected
++Note with some trickery this can be used to find out what kinda sensor is
++detected see the Linux kernel driver for an example with many comments on
++how todo this.
++
++Byte 1:
++Temp sensor: warning threshold (scale as bank 0x21)
++Volt sensor: min threshold (scale as bank 0x21)
++
++Byte 2:
++Temp sensor: shutdown threshold (scale as bank 0x21)
++Volt sensor: max threshold (scale as bank 0x21)
++
++
++Bank 0x24 PWM outputs for FAN's (R)
++Bank 0x25 PWM outputs for FAN's (W)
++-----------------------------------
++
++This bank contains 3 "sensors", for each sensor it contains 5 bytes.
++Sensor 0 usually controls the CPU fan
++Sensor 1 usually controls the NB (or chipset for single chip) fan
++Sensor 2 usually controls the System fan
++
++Byte 0:
++Flag 0x80 to enable control, Fan runs at 100% when disabled.
++low nibble (temp)sensor address at bank 0x21 used for control.
++
++Byte 1:
++0-255 = 0-12v (linear), specify voltage at which fan will rotate when under
++low threshold temp (specified in byte 3)
++
++Byte 2:
++0-255 = 0-12v (linear), specify voltage at which fan will rotate when above
++high threshold temp (specified in byte 4)
++
++Byte 3:
++Low threshold temp (scale as bank 0x21)
++
++byte 4:
++High threshold temp (scale as bank 0x21)
++
++
++Bank 0x26 Sensors Bank2 Values / Readings (R)
++---------------------------------------------
++
++This bank contains 6 sensors (AFAIK), for each sensor it contains 1 byte.
++So far the following sensors are known to be available on all motherboards:
++Sensor 0: CPU fan speed
++Sensor 1: NB (or chipset for single chip) fan speed
++Sensor 2: SYS fan speed
++
++Byte 0:
++This byte holds the reading from the sensor. 0-255 = 0-15300 (linear)
++
++
++Bank 0x27 Sensors Bank2 Settings (R)
++Bank 0x28 Sensors Bank2 Settings (W)
++------------------------------------
++
++This bank contains 6 sensors (AFAIK), for each sensor it contains 2 bytes.
++
++Byte 0:
++Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
++Bit 0: Give an alarm if measured rpm is under the min threshold (RW)
++Bit 3: Beep if alarm (RW)
++Bit 7: Shutdown if alarm persist for more then 4 seconds (RW)
++
++Byte 1:
++min threshold (scale as bank 0x26)
++
++
++Warning for the adventerous
++===========================
++
++A word of caution to those who want to experiment and see if they can figure
++the voltage / clock programming out, I tried reading and only reading banks
++0-0x30 with the reading code used for the sensor banks (0x20-0x28) and this
++resulted in a _permanent_ reprogramming of the voltages, luckily I had the
++sensors part configured so that it would shutdown my system on any out of spec
++voltages which proprably safed my computer (after a reboot I managed to
++immediatly enter the bios and reload the defaults). This probably means that
++the read/write cycle for the non sensor part is different from the sensor part.
+--- gregkh-2.6.orig/MAINTAINERS
++++ gregkh-2.6/MAINTAINERS
+@@ -181,6 +181,12 @@ M: bcrl@kvack.org
+ L: linux-aio@kvack.org
+ S: Supported
+
++ABIT UGURU HARDWARE MONITOR DRIVER
++P: Hans de Goede
++M: j.w.r.degoede@hhs.nl
++L: lm-sensors@lm-sensors.org
++S: Maintained
++
+ ACENIC DRIVER
+ P: Jes Sorensen
+ M: jes@trained-monkey.org
+--- gregkh-2.6.orig/drivers/hwmon/Kconfig
++++ gregkh-2.6/drivers/hwmon/Kconfig
+@@ -27,6 +27,18 @@ config HWMON_VID
+ tristate
+ default n
+
++config SENSORS_ABITUGURU
++ tristate "Abit uGuru"
++ depends on HWMON && EXPERIMENTAL
++ help
++ If you say yes here you get support for the Abit uGuru chips
++ sensor part. The voltage and frequency control parts of the Abit
++ uGuru are not supported. The Abit uGuru chip can be found on Abit
++ uGuru featuring motherboards (most modern Abit motherboards).
++
++ This driver can also be built as a module. If so, the module
++ will be called abituguru.
++
+ config SENSORS_ADM1021
+ tristate "Analog Devices ADM1021 and compatibles"
+ depends on HWMON && I2C
+--- gregkh-2.6.orig/drivers/hwmon/Makefile
++++ gregkh-2.6/drivers/hwmon/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_SENSORS_W83792D) += w83792d
+ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
+ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
+
++obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
+ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
+ obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
+ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
+--- /dev/null
++++ gregkh-2.6/drivers/hwmon/abituguru.c
+@@ -0,0 +1,1391 @@
++/*
++ abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.nl>
++
++ 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.
++*/
++/*
++ This driver supports the sensor part of the custom Abit uGuru chip found
++ on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
++ etc voltage & frequency control is not supported!
++*/
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/jiffies.h>
++#include <linux/mutex.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <asm/io.h>
++
++/* Banks */
++#define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */
++#define ABIT_UGURU_SENSOR_BANK1 0x21 /* 16x volt and temp */
++#define ABIT_UGURU_FAN_PWM 0x24 /* 3x 5 bytes */
++#define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */
++/* max nr of sensors in bank2, currently mb's with max 6 fans are known */
++#define ABIT_UGURU_MAX_BANK2_SENSORS 6
++/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
++#define ABIT_UGURU_MAX_PWMS 5
++/* uGuru sensor bank 1 flags */ /* Alarm if: */
++#define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */
++#define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */
++#define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */
++#define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */
++#define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */
++#define ABIT_UGURU_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */
++/* uGuru sensor bank 2 flags */ /* Alarm if: */
++#define ABIT_UGURU_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */
++/* uGuru sensor bank common flags */
++#define ABIT_UGURU_BEEP_ENABLE 0x08 /* beep if alarm */
++#define ABIT_UGURU_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */
++/* uGuru fan PWM (speed control) flags */
++#define ABIT_UGURU_FAN_PWM_ENABLE 0x80 /* enable speed control */
++/* Values used for conversion */
++#define ABIT_UGURU_FAN_MAX 15300 /* RPM */
++/* Bank1 sensor types */
++#define ABIT_UGURU_IN_SENSOR 0
++#define ABIT_UGURU_TEMP_SENSOR 1
++#define ABIT_UGURU_NC 2
++/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
++ convert them to params. */
++/* 250 was determined by trial and error, 200 works most of the time, but not
++ always. I assume this is cpu-speed independent, since the ISA-bus and not
++ the CPU should be the bottleneck. Note that 250 sometimes is still not
++ enough (only reported on AN7 mb) this is handled by a higher layer. */
++#define ABIT_UGURU_WAIT_TIMEOUT 250
++/* Normally all expected status in abituguru_ready, are reported after the
++ first read, but sometimes not and we need to poll, 5 polls was not enough
++ 50 sofar is. */
++#define ABIT_UGURU_READY_TIMEOUT 50
++/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
++#define ABIT_UGURU_MAX_RETRIES 3
++#define ABIT_UGURU_RETRY_DELAY (HZ/5)
++/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is a error */
++#define ABIT_UGURU_MAX_TIMEOUTS 2
++
++/* All the variables below are named identical to the oguru and oguru2 programs
++ reverse engineered by Olle Sandberg, hence the names might not be 100%
++ logical. I could come up with better names, but I prefer keeping the names
++ identical so that this driver can be compared with his work more easily. */
++/* Two i/o-ports are used by uGuru */
++#define ABIT_UGURU_BASE 0x00E0
++/* Used to tell uGuru what to read and to read the actual data */
++#define ABIT_UGURU_CMD 0x00
++/* Mostly used to check if uGuru is busy */
++#define ABIT_UGURU_DATA 0x04
++#define ABIT_UGURU_REGION_LENGTH 5
++/* uGuru status' */
++#define ABIT_UGURU_STATUS_WRITE 0x00 /* Ready to be written */
++#define ABIT_UGURU_STATUS_READ 0x01 /* Ready to be read */
++#define ABIT_UGURU_STATUS_INPUT 0x08 /* More input */
++#define ABIT_UGURU_STATUS_READY 0x09 /* Ready to be written */
++/* utility macros */
++#define ABIT_UGURU_NAME "abituguru"
++#define ABIT_UGURU_DEBUG(level, format, arg...) \
++ if (level <= verbose) \
++ printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
++
++/* Constants */
++/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
++static const int abituguru_bank1_max_value[2] = { 3494, 255000 };
++/* Min / Max allowed values for sensor2 (fan) alarm threshold, these values
++ correspond to 300-3000 RPM */
++static const u8 abituguru_bank2_min_threshold = 5;
++static const u8 abituguru_bank2_max_threshold = 50;
++/* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
++ are temperature trip points. */
++static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 };
++/* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
++ special case the minium allowed pwm% setting for this is 30% (77) on
++ some MB's this special case is handled in the code! */
++static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 };
++static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
++
++
++/* Insmod parameters */
++static int force;
++module_param(force, bool, 0);
++MODULE_PARM_DESC(force, "Set to one to force detection.");
++static int fan_sensors;
++module_param(fan_sensors, int, 0);
++MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
++ "(0 = autodetect)");
++static int pwms;
++module_param(pwms, int, 0);
++MODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru "
++ "(0 = autodetect)");
++
++/* Default verbose is 2, since this driver is still in the testing phase */
++static int verbose = 2;
++module_param(verbose, int, 0644);
++MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
++ " 0 normal output\n"
++ " 1 + verbose error reporting\n"
++ " 2 + sensors type probing info\n"
++ " 3 + retryable error reporting");
++
++
++/* For the Abit uGuru, we need to keep some data in memory.
++ The structure is dynamically allocated, at the same time when a new
++ abituguru device is allocated. */
++struct abituguru_data {
++ struct class_device *class_dev; /* hwmon registered device */
++ struct mutex update_lock; /* protect access to data and uGuru */
++ unsigned long last_updated; /* In jiffies */
++ unsigned short addr; /* uguru base address */
++ char uguru_ready; /* is the uguru in ready state? */
++ unsigned char update_timeouts; /* number of update timeouts since last
++ successful update */
++
++ /* The sysfs attr and their names are generated automatically, for bank1
++ we cannot use a predefined array because we don't know beforehand
++ of a sensor is a volt or a temp sensor, for bank2 and the pwms its
++ easier todo things the same way. For in sensors we have 9 (temp 7)
++ sysfs entries per sensor, for bank2 and pwms 6. */
++ struct sensor_device_attribute_2 sysfs_attr[16 * 9 +
++ ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
++ /* Buffer to store the dynamically generated sysfs names, we need 2120
++ bytes for bank1 (worst case scenario of 16 in sensors), 444 bytes
++ for fan1-6 and 738 bytes for pwm1-6 + some room to spare in case I
++ miscounted :) */
++ char bank1_names[3400];
++
++ /* Bank 1 data */
++ u8 bank1_sensors[2]; /* number of [0] in, [1] temp sensors */
++ u8 bank1_address[2][16];/* addresses of [0] in, [1] temp sensors */
++ u8 bank1_value[16];
++ /* This array holds 16 x 3 entries for all the bank 1 sensor settings
++ (flags, min, max for voltage / flags, warn, shutdown for temp). */
++ u8 bank1_settings[16][3];
++ /* Maximum value for each sensor used for scaling in mV/millidegrees
++ Celsius. */
++ int bank1_max_value[16];
++
++ /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
++ u8 bank2_sensors; /* actual number of bank2 sensors found */
++ u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS];
++ u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */
++
++ /* Alarms 2 bytes for bank1, 1 byte for bank2 */
++ u8 alarms[3];
++
++ /* Fan PWM (speed control) 5 bytes per PWM */
++ u8 pwms; /* actual number of pwms found */
++ u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
++};
++
++/* wait till the uguru is in the specified state */
++static int abituguru_wait(struct abituguru_data *data, u8 state)
++{
++ int timeout = ABIT_UGURU_WAIT_TIMEOUT;
++
++ while (inb_p(data->addr + ABIT_UGURU_DATA) != state) {
++ timeout--;
++ if (timeout == 0)
++ return -EBUSY;
++ }
++ return 0;
++}
++
++/* Put the uguru in ready for input state */
++static int abituguru_ready(struct abituguru_data *data)
++{
++ int timeout = ABIT_UGURU_READY_TIMEOUT;
++
++ if (data->uguru_ready)
++ return 0;
++
++ /* Reset? / Prepare for next read/write cycle */
++ outb(0x00, data->addr + ABIT_UGURU_DATA);
++
++ /* Wait till the uguru is ready */
++ if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) {
++ ABIT_UGURU_DEBUG(1,
++ "timeout exceeded waiting for ready state\n");
++ return -EIO;
++ }
++
++ /* Cmd port MUST be read now and should contain 0xAC */
++ while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
++ timeout--;
++ if (timeout == 0) {
++ ABIT_UGURU_DEBUG(1,
++ "CMD reg does not hold 0xAC after ready command\n");
++ return -EIO;
++ }
++ }
++
++ /* After this the ABIT_UGURU_DATA port should contain
++ ABIT_UGURU_STATUS_INPUT */
++ timeout = ABIT_UGURU_READY_TIMEOUT;
++ while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) {
++ timeout--;
++ if (timeout == 0) {
++ ABIT_UGURU_DEBUG(1,
++ "state != more input after ready command\n");
++ return -EIO;
++ }
++ }
++
++ data->uguru_ready = 1;
++ return 0;
++}
++
++/* Send the bank and then sensor address to the uGuru for the next read/write
++ cycle. This function gets called as the first part of a read/write by
++ abituguru_read and abituguru_write. This function should never be
++ called by any other function. */
++static int abituguru_send_address(struct abituguru_data *data,
++ u8 bank_addr, u8 sensor_addr, int retries)
++{
++ /* assume the caller does error handling itself if it has not requested
++ any retries, and thus be quiet. */
++ int report_errors = retries;
++
++ for (;;) {
++ /* Make sure the uguru is ready and then send the bank address,
++ after this the uguru is no longer "ready". */
++ if (abituguru_ready(data) != 0)
++ return -EIO;
++ outb(bank_addr, data->addr + ABIT_UGURU_DATA);
++ data->uguru_ready = 0;
++
++ /* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
++ and send the sensor addr */
++ if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) {
++ if (retries) {
++ ABIT_UGURU_DEBUG(3, "timeout exceeded "
++ "waiting for more input state, %d "
++ "tries remaining\n", retries);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(ABIT_UGURU_RETRY_DELAY);
++ retries--;
++ continue;
++ }
++ if (report_errors)
++ ABIT_UGURU_DEBUG(1, "timeout exceeded "
++ "waiting for more input state "
++ "(bank: %d)\n", (int)bank_addr);
++ return -EBUSY;
++ }
++ outb(sensor_addr, data->addr + ABIT_UGURU_CMD);
++ return 0;
++ }
++}
++
++/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
++ result in buf, retry the send address part of the read retries times. */
++static int abituguru_read(struct abituguru_data *data,
++ u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries)
++{
++ int i;
++
++ /* Send the address */
++ i = abituguru_send_address(data, bank_addr, sensor_addr, retries);
++ if (i)
++ return i;
++
++ /* And read the data */
++ for (i = 0; i < count; i++) {
++ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
++ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
++ "read state (bank: %d, sensor: %d)\n",
++ (int)bank_addr, (int)sensor_addr);
++ break;
++ }
++ buf[i] = inb(data->addr + ABIT_UGURU_CMD);
++ }
++
++ /* Last put the chip back in ready state */
++ abituguru_ready(data);
++
++ return i;
++}
++
++/* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
++ address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */
++static int abituguru_write(struct abituguru_data *data,
++ u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
++{
++ int i;
++
++ /* Send the address */
++ i = abituguru_send_address(data, bank_addr, sensor_addr,
++ ABIT_UGURU_MAX_RETRIES);
++ if (i)
++ return i;
++
++ /* And write the data */
++ for (i = 0; i < count; i++) {
++ if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) {
++ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
++ "write state (bank: %d, sensor: %d)\n",
++ (int)bank_addr, (int)sensor_addr);
++ break;
++ }
++ outb(buf[i], data->addr + ABIT_UGURU_CMD);
++ }
++
++ /* Now we need to wait till the chip is ready to be read again,
++ don't ask why */
++ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
++ ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
++ "after write (bank: %d, sensor: %d)\n", (int)bank_addr,
++ (int)sensor_addr);
++ return -EIO;
++ }
++
++ /* Cmd port MUST be read now and should contain 0xAC */
++ if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
++ ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write "
++ "(bank: %d, sensor: %d)\n", (int)bank_addr,
++ (int)sensor_addr);
++ return -EIO;
++ }
++
++ /* Last put the chip back in ready state */
++ abituguru_ready(data);
++
++ return i;
++}
++
++/* Detect sensor type. Temp and Volt sensors are enabled with
++ different masks and will ignore enable masks not meant for them.
++ This enables us to test what kind of sensor we're dealing with.
++ By setting the alarm thresholds so that we will always get an
++ alarm for sensor type X and then enabling the sensor as sensor type
++ X, if we then get an alarm it is a sensor of type X. */
++static int __devinit
++abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
++ u8 sensor_addr)
++{
++ u8 val, buf[3];
++ int ret = ABIT_UGURU_NC;
++
++ /* First read the sensor and the current settings */
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
++ 1, ABIT_UGURU_MAX_RETRIES) != 1)
++ return -EIO;
++
++ /* Test val is sane / usable for sensor type detection. */
++ if ((val < 10u) || (val > 240u)) {
++ printk(KERN_WARNING ABIT_UGURU_NAME
++ ": bank1-sensor: %d reading (%d) too close to limits, "
++ "unable to determine sensor type, skipping sensor\n",
++ (int)sensor_addr, (int)val);
++ /* assume no sensor is there for sensors for which we can't
++ determine the sensor type because their reading is too close
++ to their limits, this usually means no sensor is there. */
++ return ABIT_UGURU_NC;
++ }
++
++ ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
++ /* Volt sensor test, enable volt low alarm, set min value ridicously
++ high. If its a volt sensor this should always give us an alarm. */
++ buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
++ buf[1] = 245;
++ buf[2] = 250;
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
++ buf, 3) != 3)
++ return -EIO;
++ /* Now we need 20 ms to give the uguru time to read the sensors
++ and raise a voltage alarm */
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(HZ/50);
++ /* Check for alarm and check the alarm is a volt low alarm. */
++ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
++ ABIT_UGURU_MAX_RETRIES) != 3)
++ return -EIO;
++ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
++ sensor_addr, buf, 3,
++ ABIT_UGURU_MAX_RETRIES) != 3)
++ return -EIO;
++ if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
++ /* Restore original settings */
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
++ sensor_addr,
++ data->bank1_settings[sensor_addr],
++ 3) != 3)
++ return -EIO;
++ ABIT_UGURU_DEBUG(2, " found volt sensor\n");
++ return ABIT_UGURU_IN_SENSOR;
++ } else
++ ABIT_UGURU_DEBUG(2, " alarm raised during volt "
++ "sensor test, but volt low flag not set\n");
++ } else
++ ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
++ "test\n");
++
++ /* Temp sensor test, enable sensor as a temp sensor, set beep value
++ ridicously low (but not too low, otherwise uguru ignores it).
++ If its a temp sensor this should always give us an alarm. */
++ buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE;
++ buf[1] = 5;
++ buf[2] = 10;
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
++ buf, 3) != 3)
++ return -EIO;
++ /* Now we need 50 ms to give the uguru time to read the sensors
++ and raise a temp alarm */
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(HZ/20);
++ /* Check for alarm and check the alarm is a temp high alarm. */
++ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
++ ABIT_UGURU_MAX_RETRIES) != 3)
++ return -EIO;
++ if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
++ sensor_addr, buf, 3,
++ ABIT_UGURU_MAX_RETRIES) != 3)
++ return -EIO;
++ if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
++ ret = ABIT_UGURU_TEMP_SENSOR;
++ ABIT_UGURU_DEBUG(2, " found temp sensor\n");
++ } else
++ ABIT_UGURU_DEBUG(2, " alarm raised during temp "
++ "sensor test, but temp high flag not set\n");
++ } else
++ ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor "
++ "test\n");
++
++ /* Restore original settings */
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
++ data->bank1_settings[sensor_addr], 3) != 3)
++ return -EIO;
++
++ return ret;
++}
++
++/* These functions try to find out how many sensors there are in bank2 and how
++ many pwms there are. The purpose of this is to make sure that we don't give
++ the user the possibility to change settings for non-existent sensors / pwm.
++ The uGuru will happily read / write whatever memory happens to be after the
++ memory storing the PWM settings when reading/writing to a PWM which is not
++ there. Notice even if we detect a PWM which doesn't exist we normally won't
++ write to it, unless the user tries to change the settings.
++
++ Although the uGuru allows reading (settings) from non existing bank2
++ sensors, my version of the uGuru does seem to stop writing to them, the
++ write function above aborts in this case with:
++ "CMD reg does not hold 0xAC after write"
++
++ Notice these 2 tests are non destructive iow read-only tests, otherwise
++ they would defeat their purpose. Although for the bank2_sensors detection a
++ read/write test would be feasible because of the reaction above, I've
++ however opted to stay on the safe side. */
++static void __devinit
++abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
++{
++ int i;
++
++ if (fan_sensors) {
++ data->bank2_sensors = fan_sensors;
++ ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
++ "\"fan_sensors\" module param\n",
++ (int)data->bank2_sensors);
++ return;
++ }
++
++ ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n");
++ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
++ /* 0x89 are the known used bits:
++ -0x80 enable shutdown
++ -0x08 enable beep
++ -0x01 enable alarm
++ All other bits should be 0, but on some motherboards
++ 0x40 (bit 6) is also high, at least for fan1 */
++ if ((!i && (data->bank2_settings[i][0] & ~0xC9)) ||
++ (i && (data->bank2_settings[i][0] & ~0x89))) {
++ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
++ "to be a fan sensor: settings[0] = %02X\n",
++ i, (unsigned int)data->bank2_settings[i][0]);
++ break;
++ }
++
++ /* check if the threshold is within the allowed range */
++ if (data->bank2_settings[i][1] <
++ abituguru_bank2_min_threshold) {
++ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
++ "to be a fan sensor: the threshold (%d) is "
++ "below the minimum (%d)\n", i,
++ (int)data->bank2_settings[i][1],
++ (int)abituguru_bank2_min_threshold);
++ break;
++ }
++ if (data->bank2_settings[i][1] >
++ abituguru_bank2_max_threshold) {
++ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
++ "to be a fan sensor: the threshold (%d) is "
++ "above the maximum (%d)\n", i,
++ (int)data->bank2_settings[i][1],
++ (int)abituguru_bank2_max_threshold);
++ break;
++ }
++ }
++
++ data->bank2_sensors = i;
++ ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n",
++ (int)data->bank2_sensors);
++}
++
++static void __devinit
++abituguru_detect_no_pwms(struct abituguru_data *data)
++{
++ int i, j;
++
++ if (pwms) {
++ data->pwms = pwms;
++ ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
++ "\"pwms\" module param\n", (int)data->pwms);
++ return;
++ }
++
++ ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n");
++ for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
++ /* 0x80 is the enable bit and the low
++ nibble is which temp sensor to use,
++ the other bits should be 0 */
++ if (data->pwm_settings[i][0] & ~0x8F) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
++ "to be a pwm channel: settings[0] = %02X\n",
++ i, (unsigned int)data->pwm_settings[i][0]);
++ break;
++ }
++
++ /* the low nibble must correspond to one of the temp sensors
++ we've found */
++ for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR];
++ j++) {
++ if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] ==
++ (data->pwm_settings[i][0] & 0x0F))
++ break;
++ }
++ if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
++ "to be a pwm channel: %d is not a valid temp "
++ "sensor address\n", i,
++ data->pwm_settings[i][0] & 0x0F);
++ break;
++ }
++
++ /* check if all other settings are within the allowed range */
++ for (j = 1; j < 5; j++) {
++ u8 min;
++ /* special case pwm1 min pwm% */
++ if ((i == 0) && ((j == 1) || (j == 2)))
++ min = 77;
++ else
++ min = abituguru_pwm_min[j];
++ if (data->pwm_settings[i][j] < min) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does "
++ "not seem to be a pwm channel: "
++ "setting %d (%d) is below the minimum "
++ "value (%d)\n", i, j,
++ (int)data->pwm_settings[i][j],
++ (int)min);
++ goto abituguru_detect_no_pwms_exit;
++ }
++ if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does "
++ "not seem to be a pwm channel: "
++ "setting %d (%d) is above the maximum "
++ "value (%d)\n", i, j,
++ (int)data->pwm_settings[i][j],
++ (int)abituguru_pwm_max[j]);
++ goto abituguru_detect_no_pwms_exit;
++ }
++ }
++
++ /* check that min temp < max temp and min pwm < max pwm */
++ if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
++ "to be a pwm channel: min pwm (%d) >= "
++ "max pwm (%d)\n", i,
++ (int)data->pwm_settings[i][1],
++ (int)data->pwm_settings[i][2]);
++ break;
++ }
++ if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) {
++ ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem "
++ "to be a pwm channel: min temp (%d) >= "
++ "max temp (%d)\n", i,
++ (int)data->pwm_settings[i][3],
++ (int)data->pwm_settings[i][4]);
++ break;
++ }
++ }
++
++abituguru_detect_no_pwms_exit:
++ data->pwms = i;
++ ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms);
++}
++
++/* Following are the sysfs callback functions. These functions expect:
++ sensor_device_attribute_2->index: sensor address/offset in the bank
++ sensor_device_attribute_2->nr: register offset, bitmask or NA. */
++static struct abituguru_data *abituguru_update_device(struct device *dev);
++
++static ssize_t show_bank1_value(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = abituguru_update_device(dev);
++ if (!data)
++ return -EIO;
++ return sprintf(buf, "%d\n", (data->bank1_value[attr->index] *
++ data->bank1_max_value[attr->index] + 128) / 255);
++}
++
++static ssize_t show_bank1_setting(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ return sprintf(buf, "%d\n",
++ (data->bank1_settings[attr->index][attr->nr] *
++ data->bank1_max_value[attr->index] + 128) / 255);
++}
++
++static ssize_t show_bank2_value(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = abituguru_update_device(dev);
++ if (!data)
++ return -EIO;
++ return sprintf(buf, "%d\n", (data->bank2_value[attr->index] *
++ ABIT_UGURU_FAN_MAX + 128) / 255);
++}
++
++static ssize_t show_bank2_setting(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ return sprintf(buf, "%d\n",
++ (data->bank2_settings[attr->index][attr->nr] *
++ ABIT_UGURU_FAN_MAX + 128) / 255);
++}
++
++static ssize_t store_bank1_setting(struct device *dev, struct device_attribute
++ *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ u8 val = (simple_strtoul(buf, NULL, 10) * 255 +
++ data->bank1_max_value[attr->index]/2) /
++ data->bank1_max_value[attr->index];
++ ssize_t ret = count;
++
++ mutex_lock(&data->update_lock);
++ if (data->bank1_settings[attr->index][attr->nr] != val) {
++ u8 orig_val = data->bank1_settings[attr->index][attr->nr];
++ data->bank1_settings[attr->index][attr->nr] = val;
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
++ attr->index, data->bank1_settings[attr->index],
++ 3) <= attr->nr) {
++ data->bank1_settings[attr->index][attr->nr] = orig_val;
++ ret = -EIO;
++ }
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t store_bank2_setting(struct device *dev, struct device_attribute
++ *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) /
++ ABIT_UGURU_FAN_MAX;
++ ssize_t ret = count;
++
++ /* this check can be done before taking the lock */
++ if ((val < abituguru_bank2_min_threshold) ||
++ (val > abituguru_bank2_max_threshold))
++ return -EINVAL;
++
++ mutex_lock(&data->update_lock);
++ if (data->bank2_settings[attr->index][attr->nr] != val) {
++ u8 orig_val = data->bank2_settings[attr->index][attr->nr];
++ data->bank2_settings[attr->index][attr->nr] = val;
++ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2,
++ attr->index, data->bank2_settings[attr->index],
++ 2) <= attr->nr) {
++ data->bank2_settings[attr->index][attr->nr] = orig_val;
++ ret = -EIO;
++ }
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t show_bank1_alarm(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = abituguru_update_device(dev);
++ if (!data)
++ return -EIO;
++ /* See if the alarm bit for this sensor is set, and if the
++ alarm matches the type of alarm we're looking for (for volt
++ it can be either low or high). The type is stored in a few
++ readonly bits in the settings part of the relevant sensor.
++ The bitmask of the type is passed to us in attr->nr. */
++ if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) &&
++ (data->bank1_settings[attr->index][0] & attr->nr))
++ return sprintf(buf, "1\n");
++ else
++ return sprintf(buf, "0\n");
++}
++
++static ssize_t show_bank2_alarm(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = abituguru_update_device(dev);
++ if (!data)
++ return -EIO;
++ if (data->alarms[2] & (0x01 << attr->index))
++ return sprintf(buf, "1\n");
++ else
++ return sprintf(buf, "0\n");
++}
++
++static ssize_t show_bank1_mask(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ if (data->bank1_settings[attr->index][0] & attr->nr)
++ return sprintf(buf, "1\n");
++ else
++ return sprintf(buf, "0\n");
++}
++
++static ssize_t show_bank2_mask(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ if (data->bank2_settings[attr->index][0] & attr->nr)
++ return sprintf(buf, "1\n");
++ else
++ return sprintf(buf, "0\n");
++}
++
++static ssize_t store_bank1_mask(struct device *dev,
++ struct device_attribute *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ int mask = simple_strtoul(buf, NULL, 10);
++ ssize_t ret = count;
++ u8 orig_val;
++
++ mutex_lock(&data->update_lock);
++ orig_val = data->bank1_settings[attr->index][0];
++
++ if (mask)
++ data->bank1_settings[attr->index][0] |= attr->nr;
++ else
++ data->bank1_settings[attr->index][0] &= ~attr->nr;
++
++ if ((data->bank1_settings[attr->index][0] != orig_val) &&
++ (abituguru_write(data,
++ ABIT_UGURU_SENSOR_BANK1 + 2, attr->index,
++ data->bank1_settings[attr->index], 3) < 1)) {
++ data->bank1_settings[attr->index][0] = orig_val;
++ ret = -EIO;
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t store_bank2_mask(struct device *dev,
++ struct device_attribute *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ int mask = simple_strtoul(buf, NULL, 10);
++ ssize_t ret = count;
++ u8 orig_val;
++
++ mutex_lock(&data->update_lock);
++ orig_val = data->bank2_settings[attr->index][0];
++
++ if (mask)
++ data->bank2_settings[attr->index][0] |= attr->nr;
++ else
++ data->bank2_settings[attr->index][0] &= ~attr->nr;
++
++ if ((data->bank2_settings[attr->index][0] != orig_val) &&
++ (abituguru_write(data,
++ ABIT_UGURU_SENSOR_BANK2 + 2, attr->index,
++ data->bank2_settings[attr->index], 2) < 1)) {
++ data->bank2_settings[attr->index][0] = orig_val;
++ ret = -EIO;
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++/* Fan PWM (speed control) */
++static ssize_t show_pwm_setting(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] *
++ abituguru_pwm_settings_multiplier[attr->nr]);
++}
++
++static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
++ *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ u8 min, val = (simple_strtoul(buf, NULL, 10) +
++ abituguru_pwm_settings_multiplier[attr->nr]/2) /
++ abituguru_pwm_settings_multiplier[attr->nr];
++ ssize_t ret = count;
++
++ /* special case pwm1 min pwm% */
++ if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2)))
++ min = 77;
++ else
++ min = abituguru_pwm_min[attr->nr];
++
++ /* this check can be done before taking the lock */
++ if ((val < min) || (val > abituguru_pwm_max[attr->nr]))
++ return -EINVAL;
++
++ mutex_lock(&data->update_lock);
++ /* this check needs to be done after taking the lock */
++ if ((attr->nr & 1) &&
++ (val >= data->pwm_settings[attr->index][attr->nr + 1]))
++ ret = -EINVAL;
++ else if (!(attr->nr & 1) &&
++ (val <= data->pwm_settings[attr->index][attr->nr - 1]))
++ ret = -EINVAL;
++ else if (data->pwm_settings[attr->index][attr->nr] != val) {
++ u8 orig_val = data->pwm_settings[attr->index][attr->nr];
++ data->pwm_settings[attr->index][attr->nr] = val;
++ if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
++ attr->index, data->pwm_settings[attr->index],
++ 5) <= attr->nr) {
++ data->pwm_settings[attr->index][attr->nr] =
++ orig_val;
++ ret = -EIO;
++ }
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t show_pwm_sensor(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ int i;
++ /* We need to walk to the temp sensor addresses to find what
++ the userspace id of the configured temp sensor is. */
++ for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++)
++ if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] ==
++ (data->pwm_settings[attr->index][0] & 0x0F))
++ return sprintf(buf, "%d\n", i+1);
++
++ return -ENXIO;
++}
++
++static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute
++ *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ unsigned long val = simple_strtoul(buf, NULL, 10) - 1;
++ ssize_t ret = count;
++
++ mutex_lock(&data->update_lock);
++ if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
++ u8 orig_val = data->pwm_settings[attr->index][0];
++ u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
++ data->pwm_settings[attr->index][0] &= 0xF0;
++ data->pwm_settings[attr->index][0] |= address;
++ if (data->pwm_settings[attr->index][0] != orig_val) {
++ if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
++ attr->index,
++ data->pwm_settings[attr->index],
++ 5) < 1) {
++ data->pwm_settings[attr->index][0] = orig_val;
++ ret = -EIO;
++ }
++ }
++ }
++ else
++ ret = -EINVAL;
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t show_pwm_enable(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ int res = 0;
++ if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE)
++ res = 2;
++ return sprintf(buf, "%d\n", res);
++}
++
++static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
++ *devattr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ u8 orig_val, user_val = simple_strtoul(buf, NULL, 10);
++ ssize_t ret = count;
++
++ mutex_lock(&data->update_lock);
++ orig_val = data->pwm_settings[attr->index][0];
++ switch (user_val) {
++ case 0:
++ data->pwm_settings[attr->index][0] &=
++ ~ABIT_UGURU_FAN_PWM_ENABLE;
++ break;
++ case 2:
++ data->pwm_settings[attr->index][0] |=
++ ABIT_UGURU_FAN_PWM_ENABLE;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ if ((data->pwm_settings[attr->index][0] != orig_val) &&
++ (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
++ attr->index, data->pwm_settings[attr->index],
++ 5) < 1)) {
++ data->pwm_settings[attr->index][0] = orig_val;
++ ret = -EIO;
++ }
++ mutex_unlock(&data->update_lock);
++ return ret;
++}
++
++static ssize_t show_name(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return sprintf(buf, "%s\n", ABIT_UGURU_NAME);
++}
++
++/* Sysfs attr templates, the real entries are generated automatically. */
++static const
++struct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = {
++ {
++ SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0),
++ SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting,
++ store_bank1_setting, 1, 0),
++ SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL,
++ ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0),
++ SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting,
++ store_bank1_setting, 2, 0),
++ SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL,
++ ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0),
++ SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
++ SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
++ SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0),
++ SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0),
++ }, {
++ SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0),
++ SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL,
++ ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0),
++ SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting,
++ store_bank1_setting, 1, 0),
++ SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting,
++ store_bank1_setting, 2, 0),
++ SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
++ SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
++ SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask,
++ store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0),
++ }
++};
++
++static const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = {
++ SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0),
++ SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0),
++ SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting,
++ store_bank2_setting, 1, 0),
++ SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask,
++ store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0),
++ SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask,
++ store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
++ SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask,
++ store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0),
++};
++
++static const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = {
++ SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable,
++ store_pwm_enable, 0, 0),
++ SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor,
++ store_pwm_sensor, 0, 0),
++ SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting,
++ store_pwm_setting, 1, 0),
++ SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting,
++ store_pwm_setting, 2, 0),
++ SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting,
++ store_pwm_setting, 3, 0),
++ SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting,
++ store_pwm_setting, 4, 0),
++};
++
++static const struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
++ SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
++};
++
++static int __devinit abituguru_probe(struct platform_device *pdev)
++{
++ struct abituguru_data *data;
++ int i, j, res;
++ char *sysfs_filename;
++ int sysfs_attr_i = 0;
++
++ /* El weirdo probe order, to keep the sysfs order identical to the
++ BIOS and window-appliction listing order. */
++ const u8 probe_order[16] = { 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E,
++ 0x02, 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
++
++ if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL)))
++ return -ENOMEM;
++
++ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
++ mutex_init(&data->update_lock);
++ platform_set_drvdata(pdev, data);
++
++ /* See if the uGuru is ready */
++ if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT)
++ data->uguru_ready = 1;
++
++ /* Completely read the uGuru this has 2 purposes:
++ - testread / see if one really is there.
++ - make an in memory copy of all the uguru settings for future use. */
++ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
++ data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) {
++ kfree(data);
++ return -ENODEV;
++ }
++
++ for (i = 0; i < 16; i++) {
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i,
++ &data->bank1_value[i], 1,
++ ABIT_UGURU_MAX_RETRIES) != 1) {
++ kfree(data);
++ return -ENODEV;
++ }
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i,
++ data->bank1_settings[i], 3,
++ ABIT_UGURU_MAX_RETRIES) != 3) {
++ kfree(data);
++ return -ENODEV;
++ }
++ }
++ /* Note: We don't know how many bank2 sensors / pwms there really are,
++ but in order to "detect" this we need to read the maximum amount
++ anyways. If we read sensors/pwms not there we'll just read crap
++ this can't hurt. We need the detection because we don't want
++ unwanted writes, which will hurt! */
++ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
++ &data->bank2_value[i], 1,
++ ABIT_UGURU_MAX_RETRIES) != 1) {
++ kfree(data);
++ return -ENODEV;
++ }
++ if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i,
++ data->bank2_settings[i], 2,
++ ABIT_UGURU_MAX_RETRIES) != 2) {
++ kfree(data);
++ return -ENODEV;
++ }
++ }
++ for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
++ if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i,
++ data->pwm_settings[i], 5,
++ ABIT_UGURU_MAX_RETRIES) != 5) {
++ kfree(data);
++ return -ENODEV;
++ }
++ }
++ data->last_updated = jiffies;
++
++ /* Detect sensor types and fill the sysfs attr for bank1 */
++ sysfs_filename = data->bank1_names;
++ for (i = 0; i < 16; i++) {
++ res = abituguru_detect_bank1_sensor_type(data, probe_order[i]);
++ if (res < 0) {
++ kfree(data);
++ return -ENODEV;
++ }
++ if (res == ABIT_UGURU_NC)
++ continue;
++
++ for (j = 0; j < (res ? 7 : 9); j++) {
++ const char *name_templ = abituguru_sysfs_bank1_templ[
++ res][j].dev_attr.attr.name;
++ data->sysfs_attr[sysfs_attr_i] =
++ abituguru_sysfs_bank1_templ[res][j];
++ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
++ sysfs_filename;
++ sysfs_filename += sprintf(sysfs_filename, name_templ,
++ data->bank1_sensors[res] + res) + 1;
++ data->sysfs_attr[sysfs_attr_i].index = probe_order[i];
++ sysfs_attr_i++;
++ }
++ data->bank1_max_value[probe_order[i]] =
++ abituguru_bank1_max_value[res];
++ data->bank1_address[res][data->bank1_sensors[res]] =
++ probe_order[i];
++ data->bank1_sensors[res]++;
++ }
++ /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */
++ abituguru_detect_no_bank2_sensors(data);
++ for (i = 0; i < data->bank2_sensors; i++) {
++ for (j = 0; j < 6; j++) {
++ const char *name_templ = abituguru_sysfs_fan_templ[j].
++ dev_attr.attr.name;
++ data->sysfs_attr[sysfs_attr_i] =
++ abituguru_sysfs_fan_templ[j];
++ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
++ sysfs_filename;
++ sysfs_filename += sprintf(sysfs_filename, name_templ,
++ i + 1) + 1;
++ data->sysfs_attr[sysfs_attr_i].index = i;
++ sysfs_attr_i++;
++ }
++ }
++ /* Detect number of sensors and fill the sysfs attr for pwms */
++ abituguru_detect_no_pwms(data);
++ for (i = 0; i < data->pwms; i++) {
++ for (j = 0; j < 6; j++) {
++ const char *name_templ = abituguru_sysfs_pwm_templ[j].
++ dev_attr.attr.name;
++ data->sysfs_attr[sysfs_attr_i] =
++ abituguru_sysfs_pwm_templ[j];
++ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
++ sysfs_filename;
++ sysfs_filename += sprintf(sysfs_filename, name_templ,
++ i + 1) + 1;
++ data->sysfs_attr[sysfs_attr_i].index = i;
++ sysfs_attr_i++;
++ }
++ }
++ /* Last add any "generic" entries to sysfs */
++ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) {
++ data->sysfs_attr[sysfs_attr_i] = abituguru_sysfs_attr[i];
++ sysfs_attr_i++;
++ }
++ printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
++
++ /* Register sysfs hooks */
++ data->class_dev = hwmon_device_register(&pdev->dev);
++ if (IS_ERR(data->class_dev)) {
++ kfree(data);
++ return PTR_ERR(data->class_dev);
++ }
++ for (i = 0; i < sysfs_attr_i; i++)
++ device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
++
++ return 0;
++}
++
++static int __devexit abituguru_remove(struct platform_device *pdev)
++{
++ struct abituguru_data *data = platform_get_drvdata(pdev);
++
++ platform_set_drvdata(pdev, NULL);
++ hwmon_device_unregister(data->class_dev);
++ kfree(data);
++
++ return 0;
++}
++
++static struct abituguru_data *abituguru_update_device(struct device *dev)
++{
++ int i, err;
++ struct abituguru_data *data = dev_get_drvdata(dev);
++ /* fake a complete successful read if no update necessary. */
++ char success = 1;
++
++ mutex_lock(&data->update_lock);
++ if (time_after(jiffies, data->last_updated + HZ)) {
++ success = 0;
++ if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
++ data->alarms, 3, 0)) != 3)
++ goto LEAVE_UPDATE;
++ for (i = 0; i < 16; i++) {
++ if ((err = abituguru_read(data,
++ ABIT_UGURU_SENSOR_BANK1, i,
++ &data->bank1_value[i], 1, 0)) != 1)
++ goto LEAVE_UPDATE;
++ if ((err = abituguru_read(data,
++ ABIT_UGURU_SENSOR_BANK1 + 1, i,
++ data->bank1_settings[i], 3, 0)) != 3)
++ goto LEAVE_UPDATE;
++ }
++ for (i = 0; i < data->bank2_sensors; i++)
++ if ((err = abituguru_read(data,
++ ABIT_UGURU_SENSOR_BANK2, i,
++ &data->bank2_value[i], 1, 0)) != 1)
++ goto LEAVE_UPDATE;
++ /* success! */
++ success = 1;
++ data->update_timeouts = 0;
++LEAVE_UPDATE:
++ /* handle timeout condition */
++ if (err == -EBUSY) {
++ /* No overflow please */
++ if (data->update_timeouts < 255u)
++ data->update_timeouts++;
++ if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) {
++ ABIT_UGURU_DEBUG(3, "timeout exceeded, will "
++ "try again next update\n");
++ /* Just a timeout, fake a successful read */
++ success = 1;
++ } else
++ ABIT_UGURU_DEBUG(1, "timeout exceeded %d "
++ "times waiting for more input state\n",
++ (int)data->update_timeouts);
++ }
++ /* On success set last_updated */
++ if (success)
++ data->last_updated = jiffies;
++ }
++ mutex_unlock(&data->update_lock);
++
++ if (success)
++ return data;
++ else
++ return NULL;
++}
++
++static struct platform_driver abituguru_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = ABIT_UGURU_NAME,
++ },
++ .probe = abituguru_probe,
++ .remove = __devexit_p(abituguru_remove),
++};
++
++static int __init abituguru_detect(void)
++{
++ /* See if there is an uguru there. After a reboot uGuru will hold 0x00
++ at DATA and 0xAC, when this driver has already been loaded once
++ DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
++ scenario but some will hold 0x00.
++ Some uGuru's initally hold 0x09 at DATA and will only hold 0x08
++ after reading CMD first, so CMD must be read first! */
++ u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD);
++ u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA);
++ if (((data_val == 0x00) || (data_val == 0x08)) &&
++ ((cmd_val == 0x00) || (cmd_val == 0xAC)))
++ return ABIT_UGURU_BASE;
++
++ ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = "
++ "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
++
++ if (force) {
++ printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is "
++ "present because of \"force\" parameter\n");
++ return ABIT_UGURU_BASE;
++ }
++
++ /* No uGuru found */
++ return -ENODEV;
++}
++
++static struct platform_device *abituguru_pdev;
++
++static int __init abituguru_init(void)
++{
++ int address, err;
++ struct resource res = { .flags = IORESOURCE_IO };
++
++ address = abituguru_detect();
++ if (address < 0)
++ return address;
++
++ err = platform_driver_register(&abituguru_driver);
++ if (err)
++ goto exit;
++
++ abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
++ if (!abituguru_pdev) {
++ printk(KERN_ERR ABIT_UGURU_NAME
++ ": Device allocation failed\n");
++ err = -ENOMEM;
++ goto exit_driver_unregister;
++ }
++
++ res.start = address;
++ res.end = address + ABIT_UGURU_REGION_LENGTH - 1;
++ res.name = ABIT_UGURU_NAME;
++
++ err = platform_device_add_resources(abituguru_pdev, &res, 1);
++ if (err) {
++ printk(KERN_ERR ABIT_UGURU_NAME
++ ": Device resource addition failed (%d)\n", err);
++ goto exit_device_put;
++ }
++
++ err = platform_device_add(abituguru_pdev);
++ if (err) {
++ printk(KERN_ERR ABIT_UGURU_NAME
++ ": Device addition failed (%d)\n", err);
++ goto exit_device_put;
++ }
++
++ return 0;
++
++exit_device_put:
++ platform_device_put(abituguru_pdev);
++exit_driver_unregister:
++ platform_driver_unregister(&abituguru_driver);
++exit:
++ return err;
++}
++
++static void __exit abituguru_exit(void)
++{
++ platform_device_unregister(abituguru_pdev);
++ platform_driver_unregister(&abituguru_driver);
++}
++
++MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
++MODULE_DESCRIPTION("Abit uGuru Sensor device");
++MODULE_LICENSE("GPL");
++
++module_init(abituguru_init);
++module_exit(abituguru_exit);
diff --git a/i2c/hwmon-abituguru-nofans-detect-fix.patch b/i2c/hwmon-abituguru-nofans-detect-fix.patch
new file mode 100644
index 0000000000000..0953a2fe07a45
--- /dev/null
+++ b/i2c/hwmon-abituguru-nofans-detect-fix.patch
@@ -0,0 +1,39 @@
+From khali@linux-fr.org Sun Jun 4 11:24:17 2006
+Date: Sun, 4 Jun 2006 20:24:11 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: abituguru: Fix fan detection
+Message-Id: <20060604202411.59d7dd3f.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-abituguru-nofans-detect-fix.patch
+
+From: Hans de Goede <j.w.r.degoede@hhs.nl>
+
+One of my testers had a problem where the driver only saw 2 of the 4 fan
+sensors his uGuru has, this fixes this.
+ -accept 0x40 (bit 6) being high as a valid fan sensor setting for all fans
+ not just fan 1, I have a feeling this bit indicates whether or not a fan is
+ actually connected .
+
+Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/abituguru.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/abituguru.c
++++ gregkh-2.6/drivers/hwmon/abituguru.c
+@@ -529,9 +529,8 @@ abituguru_detect_no_bank2_sensors(struct
+ -0x08 enable beep
+ -0x01 enable alarm
+ All other bits should be 0, but on some motherboards
+- 0x40 (bit 6) is also high, at least for fan1 */
+- if ((!i && (data->bank2_settings[i][0] & ~0xC9)) ||
+- (i && (data->bank2_settings[i][0] & ~0x89))) {
++ 0x40 (bit 6) is also high for some of the fans?? */
++ if (data->bank2_settings[i][0] & ~0xC9) {
+ ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem "
+ "to be a fan sensor: settings[0] = %02X\n",
+ i, (unsigned int)data->bank2_settings[i][0]);
diff --git a/i2c/hwmon-hdaps-typo.patch b/i2c/hwmon-hdaps-typo.patch
new file mode 100644
index 0000000000000..1701ce413f112
--- /dev/null
+++ b/i2c/hwmon-hdaps-typo.patch
@@ -0,0 +1,30 @@
+From khali@linux-fr.org Sun Jun 4 11:10:57 2006
+Date: Sun, 4 Jun 2006 20:10:55 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Robert Love <rlove@rlove.org>
+Subject: hwmon: Fix a typo in the hdaps driver
+Message-Id: <20060604201055.93571684.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-hdaps-typo.patch
+
+Fix a typo in the hdaps driver.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Acked-by: Robert Love <rml@novell.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/hdaps.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/hdaps.c
++++ gregkh-2.6/drivers/hwmon/hdaps.c
+@@ -41,7 +41,7 @@
+ #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_TEMP1 0x1616 /* device temperature, in Celsius */
+ #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?) */
diff --git a/i2c/hwmon-maintenance-update.patch b/i2c/hwmon-maintenance-update.patch
new file mode 100644
index 0000000000000..eb44784fd5572
--- /dev/null
+++ b/i2c/hwmon-maintenance-update.patch
@@ -0,0 +1,47 @@
+From khali@linux-fr.org Sun Jun 4 11:13:04 2006
+Date: Sun, 4 Jun 2006 20:13:01 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: hwmon: Drop some maintainers entries
+Message-Id: <20060604201301.0bc5da17.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-maintenance-update.patch
+
+I no more wish to be listed as the maintainer for the smsc47m1 and
+w83l785ts drivers. I have no test device, and people will fallback
+to me as the general hardware monitoring maintainer anyway.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ MAINTAINERS | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+--- gregkh-2.6.orig/MAINTAINERS
++++ gregkh-2.6/MAINTAINERS
+@@ -2516,12 +2516,6 @@ M: thomas@winischhofer.net
+ W: http://www.winischhofer.at/linuxsisusbvga.shtml
+ S: Maintained
+
+-SMSC47M1 HARDWARE MONITOR DRIVER
+-P: Jean Delvare
+-M: khali@linux-fr.org
+-L: lm-sensors@lm-sensors.org
+-S: Odd Fixes
+-
+ SMB FILESYSTEM
+ P: Urban Widmark
+ M: urban@teststation.com
+@@ -3134,12 +3128,6 @@ L: wbsd-devel@list.drzeus.cx
+ W: http://projects.drzeus.cx/wbsd
+ S: Maintained
+
+-W83L785TS HARDWARE MONITOR DRIVER
+-P: Jean Delvare
+-M: khali@linux-fr.org
+-L: lm-sensors@lm-sensors.org
+-S: Odd Fixes
+-
+ WATCHDOG DEVICE DRIVERS
+ P: Wim Van Sebroeck
+ M: wim@iguana.be
diff --git a/i2c/hwmon-sysfs-interface-update-1.patch b/i2c/hwmon-sysfs-interface-update-1.patch
new file mode 100644
index 0000000000000..8278021e4281e
--- /dev/null
+++ b/i2c/hwmon-sysfs-interface-update-1.patch
@@ -0,0 +1,379 @@
+From khali@linux-fr.org Sun Jun 4 11:03:42 2006
+Date: Sun, 4 Jun 2006 20:03:39 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Rudolf Marek <r.marek@sh.cvut.cz>
+Subject: hwmon: Sysfs interface documentation update, 1 of 2
+Message-Id: <20060604200339.4ba872f7.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-sysfs-interface-update-1.patch
+
+From: Rudolf Marek <r.marek@sh.cvut.cz>
+
+This patch cleans up hwmon sysfs documentation file, plus introduces
+the description of DC/PWM selection for fan speed control.
+
+Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/sysfs-interface | 183 +++++++++++++++++++++---------------
+ 1 file changed, 108 insertions(+), 75 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/hwmon/sysfs-interface
++++ gregkh-2.6/Documentation/hwmon/sysfs-interface
+@@ -69,28 +69,37 @@ to cause an alarm) is chip-dependent.
+
+ -------------------------------------------------------------------------
+
++[0-*] denotes any positive number starting from 0
++[1-*] denotes any positive number starting from 1
++RO read only value
++RW read/write value
++
++Read/write values may be read-only for some chips, depending on the
++hardware implementation.
++
+ ************
+ * Voltages *
+ ************
+
+-in[0-8]_min Voltage min value.
++in[0-*]_min Voltage min value.
+ Unit: millivolt
+- Read/Write
++ RW
+
+-in[0-8]_max Voltage max value.
++in[0-*]_max Voltage max value.
+ Unit: millivolt
+- Read/Write
++ RW
+
+-in[0-8]_input Voltage input value.
++in[0-*]_input Voltage input value.
+ Unit: millivolt
+- Read only
++ RO
++ Voltage measured on the chip pin.
+ Actual voltage depends on the scaling resistors on the
+ motherboard, as recommended in the chip datasheet.
+ This varies by chip and by motherboard.
+ Because of this variation, values are generally NOT scaled
+ by the chip driver, and must be done by the application.
+ However, some drivers (notably lm87 and via686a)
+- do scale, with various degrees of success.
++ do scale, because of internal resistors built into a chip.
+ These drivers will output the actual voltage.
+
+ Typical usage:
+@@ -104,58 +113,72 @@ in[0-8]_input Voltage input value.
+ in7_* varies
+ in8_* varies
+
+-cpu[0-1]_vid CPU core reference voltage.
++cpu[0-*]_vid CPU core reference voltage.
+ Unit: millivolt
+- Read only.
++ RO
+ Not always correct.
+
+ vrm Voltage Regulator Module version number.
+- Read only.
+- Two digit number, first is major version, second is
+- minor version.
++ RW (but changing it should no more be necessary)
++ Originally the VRM standard version multiplied by 10, but now
++ an arbitrary number, as not all standards have a version
++ number.
+ Affects the way the driver calculates the CPU core reference
+ voltage from the vid pins.
+
++Also see the Alarms section for status flags associated with voltages.
++
+
+ ********
+ * Fans *
+ ********
+
+-fan[1-3]_min Fan minimum value
++fan[1-*]_min Fan minimum value
+ Unit: revolution/min (RPM)
+- Read/Write.
++ RW
+
+-fan[1-3]_input Fan input value.
++fan[1-*]_input Fan input value.
+ Unit: revolution/min (RPM)
+- Read only.
++ RO
+
+-fan[1-3]_div Fan divisor.
++fan[1-*]_div Fan divisor.
+ Integer value in powers of two (1, 2, 4, 8, 16, 32, 64, 128).
++ RW
+ Some chips only support values 1, 2, 4 and 8.
+ Note that this is actually an internal clock divisor, which
+ affects the measurable speed range, not the read value.
+
++Also see the Alarms section for status flags associated with fans.
++
++
+ *******
+ * PWM *
+ *******
+
+-pwm[1-3] Pulse width modulation fan control.
++pwm[1-*] Pulse width modulation fan control.
+ Integer value in the range 0 to 255
+- Read/Write
++ RW
+ 255 is max or 100%.
+
+-pwm[1-3]_enable
++pwm[1-*]_enable
+ Switch PWM on and off.
+ Not always present even if fan*_pwm is.
+- 0 to turn off
+- 1 to turn on in manual mode
+- 2 to turn on in automatic mode
+- Read/Write
++ 0: turn off
++ 1: turn on in manual mode
++ 2+: turn on in automatic mode
++ Check individual chip documentation files for automatic mode details.
++ RW
++
++pwm[1-*]_mode
++ 0: DC mode
++ 1: PWM mode
++ RW
+
+ pwm[1-*]_auto_channels_temp
+ Select which temperature channels affect this PWM output in
+ auto mode. Bitfield, 1 is temp1, 2 is temp2, 4 is temp3 etc...
+ Which values are possible depend on the chip used.
++ RW
+
+ pwm[1-*]_auto_point[1-*]_pwm
+ pwm[1-*]_auto_point[1-*]_temp
+@@ -163,6 +186,7 @@ pwm[1-*]_auto_point[1-*]_temp_hyst
+ Define the PWM vs temperature curve. Number of trip points is
+ chip-dependent. Use this for chips which associate trip points
+ to PWM output channels.
++ RW
+
+ OR
+
+@@ -172,51 +196,52 @@ temp[1-*]_auto_point[1-*]_temp_hyst
+ Define the PWM vs temperature curve. Number of trip points is
+ chip-dependent. Use this for chips which associate trip points
+ to temperature channels.
++ RW
+
+
+ ****************
+ * Temperatures *
+ ****************
+
+-temp[1-3]_type Sensor type selection.
++temp[1-*]_type Sensor type selection.
+ Integers 1 to 4 or thermistor Beta value (typically 3435)
+- Read/Write.
++ RW
+ 1: PII/Celeron Diode
+ 2: 3904 transistor
+ 3: thermal diode
+ 4: thermistor (default/unknown Beta)
+ Not all types are supported by all chips
+
+-temp[1-4]_max Temperature max value.
++temp[1-*]_max Temperature max value.
+ Unit: millidegree Celcius
+- Read/Write value.
++ RW
+
+-temp[1-3]_min Temperature min value.
++temp[1-*]_min Temperature min value.
+ Unit: millidegree Celcius
+- Read/Write value.
++ RW
+
+-temp[1-3]_max_hyst
++temp[1-*]_max_hyst
+ Temperature hysteresis value for max limit.
+ Unit: millidegree Celcius
+ Must be reported as an absolute temperature, NOT a delta
+ from the max value.
+- Read/Write value.
++ RW
+
+-temp[1-4]_input Temperature input value.
++temp[1-*]_input Temperature input value.
+ Unit: millidegree Celcius
+- Read only value.
++ RO
+
+-temp[1-4]_crit Temperature critical value, typically greater than
++temp[1-*]_crit Temperature critical value, typically greater than
+ corresponding temp_max values.
+ Unit: millidegree Celcius
+- Read/Write value.
++ RW
+
+-temp[1-2]_crit_hyst
++temp[1-*]_crit_hyst
+ Temperature hysteresis value for critical limit.
+ Unit: millidegree Celcius
+ Must be reported as an absolute temperature, NOT a delta
+ from the critical value.
+- Read/Write value.
++ RW
+
+ temp[1-4]_offset
+ Temperature offset which is added to the temperature reading
+@@ -231,6 +256,8 @@ temp[1-4]_offset
+ itself, for example the thermal diode inside the CPU or
+ a thermistor nearby.
+
++Also see the Alarms section for status flags associated with temperatures.
++
+
+ ************
+ * Currents *
+@@ -239,17 +266,17 @@ temp[1-4]_offset
+ Note that no known chip provides current measurements as of writing,
+ so this part is theoretical, so to say.
+
+-curr[1-n]_max Current max value
++curr[1-*]_max Current max value
+ Unit: milliampere
+- Read/Write.
++ RW
+
+-curr[1-n]_min Current min value.
++curr[1-*]_min Current min value.
+ Unit: milliampere
+- Read/Write.
++ RW
+
+-curr[1-n]_input Current input value
++curr[1-*]_input Current input value
+ Unit: milliampere
+- Read only.
++ RO
+
+
+ **********
+@@ -263,50 +290,54 @@ Usually a given chip will either use cha
+ limit-related alarms, not both. The driver should just reflect the hardware
+ implementation.
+
+-in[0-n]_alarm
+-fan[1-n]_alarm
+-temp[1-n]_alarm
++in[0-*]_alarm
++fan[1-*]_alarm
++temp[1-*]_alarm
+ Channel alarm
+- Boolean
+- Read-only
++ 0: no alarm
++ 1: alarm
++ RO
+
+ OR
+
+-in[0-n]_min_alarm
+-in[0-n]_max_alarm
+-fan[1-n]_min_alarm
+-temp[1-n]_min_alarm
+-temp[1-n]_max_alarm
+-temp[1-n]_crit_alarm
++in[0-*]_min_alarm
++in[0-*]_max_alarm
++fan[1-*]_min_alarm
++temp[1-*]_min_alarm
++temp[1-*]_max_alarm
++temp[1-*]_crit_alarm
+ Limit alarm
+- Boolean
+- Read-only
++ 0: no alarm
++ 1: alarm
++ RO
+
+ Each input channel may have an associated fault file. This can be used
+ to notify open diodes, unconnected fans etc. where the hardware
+ supports it. When this boolean has value 1, the measurement for that
+ channel should not be trusted.
+
+-in[0-n]_input_fault
+-fan[1-n]_input_fault
+-temp[1-n]_input_fault
++in[0-*]_input_fault
++fan[1-*]_input_fault
++temp[1-*]_input_fault
+ Input fault condition
+- Boolean
+- Read-only
++ 0: no fault occured
++ 1: fault condition
++ RO
+
+ Some chips also offer the possibility to get beeped when an alarm occurs:
+
+ beep_enable Master beep enable
+- Boolean
+- Read/Write
+-
+-in[0-n]_beep
+-fan[1-n]_beep
+-temp[1-n]_beep
++ 0: no beeps
++ 1: beeps
++ RW
++
++in[0-*]_beep
++fan[1-*]_beep
++temp[1-*]_beep
+ Channel beep
+- 0 to disable.
+- 1 to enable.
+- Read/write
++ 0: disable
++ 1: enable
++ RW
+
+ In theory, a chip could provide per-limit beep masking, but no such chip
+ was seen so far.
+@@ -316,7 +347,7 @@ beeps. These interface files are depreca
+ for compatibility reasons:
+
+ alarms Alarm bitmask.
+- Read only.
++ RO
+ Integer representation of one to four bytes.
+ A '1' bit means an alarm.
+ Chips should be programmed for 'comparator' mode so that
+@@ -333,7 +364,7 @@ beep_mask Bitmask for beep.
+ Same format as 'alarms' with the same bit locations,
+ use discouraged for the same reason. Use individual
+ *_beep files instead.
+- Read/Write
++ RW
+
+
+ *********
+@@ -341,7 +372,9 @@ beep_mask Bitmask for beep.
+ *********
+
+ eeprom Raw EEPROM data in binary form.
+- Read only.
++ RO
+
+ pec Enable or disable PEC (SMBus only)
+- Read/Write
++ 0: disable
++ 1: enable
++ RW
diff --git a/i2c/hwmon-sysfs-interface-update-2.patch b/i2c/hwmon-sysfs-interface-update-2.patch
new file mode 100644
index 0000000000000..0853c07863332
--- /dev/null
+++ b/i2c/hwmon-sysfs-interface-update-2.patch
@@ -0,0 +1,138 @@
+From khali@linux-fr.org Mon Jun 5 11:31:25 2006
+Date: Mon, 5 Jun 2006 20:31:20 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Jim Cromie <jim.cromie@gmail.com>
+Subject: hwmon: Sysfs interface documentation update, 2 of 2, take 2
+Message-Id: <20060605203120.b865347e.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-sysfs-interface-update-2.patch
+
+Reword and complete certain parts of the hwmon sysfs-interface
+documentation file. Hopefully this will make things clearer for new
+driver authors.
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/hwmon/sysfs-interface | 45 +++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 16 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/hwmon/sysfs-interface
++++ gregkh-2.6/Documentation/hwmon/sysfs-interface
+@@ -3,15 +3,15 @@ Naming and data format standards for sys
+
+ The libsensors library offers an interface to the raw sensors data
+ through the sysfs interface. See libsensors documentation and source for
+-more further information. As of writing this document, libsensors
+-(from lm_sensors 2.8.3) is heavily chip-dependant. Adding or updating
++further information. As of writing this document, libsensors
++(from lm_sensors 2.8.3) is heavily chip-dependent. Adding or updating
+ support for any given chip requires modifying the library's code.
+ This is because libsensors was written for the procfs interface
+ older kernel modules were using, which wasn't standardized enough.
+ Recent versions of libsensors (from lm_sensors 2.8.2 and later) have
+ support for the sysfs interface, though.
+
+-The new sysfs interface was designed to be as chip-independant as
++The new sysfs interface was designed to be as chip-independent as
+ possible.
+
+ Note that motherboards vary widely in the connections to sensor chips.
+@@ -24,7 +24,7 @@ range using external resistors. Since th
+ can change from motherboard to motherboard, the conversions cannot be
+ hard coded into the driver and have to be done in user space.
+
+-For this reason, even if we aim at a chip-independant libsensors, it will
++For this reason, even if we aim at a chip-independent libsensors, it will
+ still require a configuration file (e.g. /etc/sensors.conf) for proper
+ values conversion, labeling of inputs and hiding of unused inputs.
+
+@@ -39,15 +39,16 @@ If you are developing a userspace applic
+ this standard.
+
+ Note that this standard isn't completely established yet, so it is subject
+-to changes, even important ones. One more reason to use the library instead
+-of accessing sysfs files directly.
++to changes. If you are writing a new hardware monitoring driver those
++features can't seem to fit in this interface, please contact us with your
++extension proposal. Keep in mind that backward compatibility must be
++preserved.
+
+ Each chip gets its own directory in the sysfs /sys/devices tree. To
+-find all sensor chips, it is easier to follow the symlinks from
+-/sys/i2c/devices/
++find all sensor chips, it is easier to follow the device symlinks from
++/sys/class/hwmon/hwmon*.
+
+-All sysfs values are fixed point numbers. To get the true value of some
+-of the values, you should divide by the specified value.
++All sysfs values are fixed point numbers.
+
+ There is only one value per file, unlike the older /proc specification.
+ The common scheme for files naming is: <type><number>_<item>. Usual
+@@ -77,6 +78,9 @@ RW read/write value
+ Read/write values may be read-only for some chips, depending on the
+ hardware implementation.
+
++All entries are optional, and should only be created in a given driver
++if the chip has the feature.
++
+ ************
+ * Voltages *
+ ************
+@@ -213,32 +217,32 @@ temp[1-*]_type Sensor type selection.
+ Not all types are supported by all chips
+
+ temp[1-*]_max Temperature max value.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius (or millivolt, see below)
+ RW
+
+ temp[1-*]_min Temperature min value.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius
+ RW
+
+ temp[1-*]_max_hyst
+ Temperature hysteresis value for max limit.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius
+ Must be reported as an absolute temperature, NOT a delta
+ from the max value.
+ RW
+
+ temp[1-*]_input Temperature input value.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius
+ RO
+
+ temp[1-*]_crit Temperature critical value, typically greater than
+ corresponding temp_max values.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius
+ RW
+
+ temp[1-*]_crit_hyst
+ Temperature hysteresis value for critical limit.
+- Unit: millidegree Celcius
++ Unit: millidegree Celsius
+ Must be reported as an absolute temperature, NOT a delta
+ from the critical value.
+ RW
+@@ -256,6 +260,15 @@ temp[1-4]_offset
+ itself, for example the thermal diode inside the CPU or
+ a thermistor nearby.
+
++Some chips measure temperature using external thermistors and an ADC, and
++report the temperature measurement as a voltage. Converting this voltage
++back to a temperature (or the other way around for limits) requires
++mathematical functions not available in the kernel, so the conversion
++must occur in user space. For these chips, all temp* files described
++above should contain values expressed in millivolt instead of millidegree
++Celsius. In other words, such temperature channels are handled as voltage
++channels by the driver.
++
+ Also see the Alarms section for status flags associated with temperatures.
+
+
diff --git a/i2c/hwmon-w83792d-add-data-lock.patch b/i2c/hwmon-w83792d-add-data-lock.patch
new file mode 100644
index 0000000000000..191f6c9144695
--- /dev/null
+++ b/i2c/hwmon-w83792d-add-data-lock.patch
@@ -0,0 +1,194 @@
+From khali@linux-fr.org Sun Jun 4 11:18:49 2006
+Date: Sun, 4 Jun 2006 20:18:45 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Yuan Mu <ymu@winbond.com.tw>
+Subject: w83792d: Add missing data access locks
+Message-Id: <20060604201845.12ea5bfe.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-w83792d-add-data-lock.patch
+
+From: Yuan Mu <ymu@winbond.com.tw>
+
+Add missing data lock in w83792d driver to avoid unexpected
+data change.
+
+Signed-off-by: Yuan Mu <ymu@winbond.com.tw>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/w83792d.c | 30 +++++++++++++++++++++++++-----
+ 1 file changed, 25 insertions(+), 5 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/w83792d.c
++++ gregkh-2.6/drivers/hwmon/w83792d.c
+@@ -372,8 +372,10 @@ static ssize_t store_in_##reg (struct de
+ u32 val; \
+ \
+ val = simple_strtoul(buf, NULL, 10); \
++ mutex_lock(&data->update_lock); \
+ 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]); \
++ mutex_unlock(&data->update_lock); \
+ \
+ return count; \
+ }
+@@ -440,9 +442,11 @@ store_fan_min(struct device *dev, struct
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
+ 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]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -475,6 +479,7 @@ store_fan_div(struct device *dev, struct
+ u8 tmp_fan_div;
+
+ /* Save fan_min */
++ mutex_lock(&data->update_lock);
+ min = FAN_FROM_REG(data->fan_min[nr],
+ DIV_FROM_REG(data->fan_div[nr]));
+
+@@ -490,6 +495,7 @@ store_fan_div(struct device *dev, struct
+ /* 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]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -544,10 +550,11 @@ static ssize_t store_temp1(struct device
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+-
++ mutex_lock(&data->update_lock);
+ data->temp1[nr] = TEMP1_TO_REG(val);
+ w83792d_write_value(client, W83792D_REG_TEMP1[nr],
+ data->temp1[nr]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -577,13 +584,14 @@ static ssize_t store_temp23(struct devic
+ s32 val;
+
+ val = simple_strtol(buf, NULL, 10);
+-
++ mutex_lock(&data->update_lock);
+ 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]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -682,6 +690,10 @@ store_pwmenable(struct device *dev, stru
+ u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp;
+
+ val = simple_strtoul(buf, NULL, 10);
++ if (val < 1 || val > 3)
++ return -EINVAL;
++
++ mutex_lock(&data->update_lock);
+ switch (val) {
+ case 1:
+ data->pwmenable[nr] = 0; /* manual mode */
+@@ -692,8 +704,6 @@ store_pwmenable(struct device *dev, stru
+ 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;
+@@ -701,6 +711,7 @@ store_pwmenable(struct device *dev, stru
+ 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);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -794,12 +805,13 @@ store_chassis_clear(struct device *dev,
+ u8 temp1 = 0, temp2 = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
+-
++ mutex_lock(&data->update_lock);
+ 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);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -832,10 +844,12 @@ store_thermal_cruise(struct device *dev,
+ val = simple_strtoul(buf, NULL, 10);
+ target_tmp = val;
+ target_tmp = target_tmp & 0x7f;
++ mutex_lock(&data->update_lock);
+ 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);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -872,6 +886,7 @@ store_tolerance(struct device *dev, stru
+ u8 tol_tmp, tol_mask;
+
+ val = simple_strtoul(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
+ tol_mask = w83792d_read_value(client,
+ W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0);
+ tol_tmp = SENSORS_LIMIT(val, 0, 15);
+@@ -882,6 +897,7 @@ store_tolerance(struct device *dev, stru
+ }
+ w83792d_write_value(client, W83792D_REG_TOLERANCE[nr],
+ tol_mask | tol_tmp);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -920,11 +936,13 @@ store_sf2_point(struct device *dev, stru
+ u8 mask_tmp = 0;
+
+ val = simple_strtoul(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
+ 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]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -984,6 +1002,7 @@ store_sf2_level(struct device *dev, stru
+ u8 mask_tmp=0, level_tmp=0;
+
+ val = simple_strtoul(buf, NULL, 10);
++ mutex_lock(&data->update_lock);
+ 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);
+@@ -993,6 +1012,7 @@ store_sf2_level(struct device *dev, stru
+ level_tmp = data->sf2_levels[index][nr] << 4;
+ }
+ w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
diff --git a/i2c/hwmon-w83792d-pwm-set-fix.patch b/i2c/hwmon-w83792d-pwm-set-fix.patch
new file mode 100644
index 0000000000000..2f31e8478640c
--- /dev/null
+++ b/i2c/hwmon-w83792d-pwm-set-fix.patch
@@ -0,0 +1,173 @@
+From khali@linux-fr.org Sun Jun 4 11:18:08 2006
+Date: Sun, 4 Jun 2006 20:18:05 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Yuan Mu <ymu@winbond.com.tw>
+Subject: w83792d: Fix setting the PWM value
+Message-Id: <20060604201805.49585bea.khali@linux-fr.org>
+Content-Disposition: inline; filename=hwmon-w83792d-pwm-set-fix.patch
+
+From: Yuan Mu <ymu@winbond.com.tw>
+
+W83792D use pwm register low 4 bits to store PWM/DC value, bit 7
+is used to store fan PWM/DC mode. The store_pwm function did not
+convert the pwm input correctly, so it may change the fan mode
+when new value is set.
+
+This fix the problem. Change the "index" value of pwm*_mode
+and pwm* SENSOR_ATTR to simplify code.
+
+Signed-off-by: Yuan Mu <ymu@winbond.com.tw>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hwmon/w83792d.c | 56 ++++++++++++++++++++++++------------------------
+ 1 file changed, 29 insertions(+), 27 deletions(-)
+
+--- gregkh-2.6.orig/drivers/hwmon/w83792d.c
++++ gregkh-2.6/drivers/hwmon/w83792d.c
+@@ -250,8 +250,6 @@ FAN_TO_REG(long rpm, int div)
+ : (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
+@@ -291,7 +289,6 @@ struct w83792d_data {
+ 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 */
+@@ -627,7 +624,7 @@ show_pwm(struct device *dev, struct devi
+ 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]));
++ return sprintf(buf, "%d\n", (data->pwm[nr] & 0x0f) << 4);
+ }
+
+ static ssize_t
+@@ -659,14 +656,16 @@ store_pwm(struct device *dev, struct dev
+ const char *buf, size_t count)
+ {
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+- int nr = sensor_attr->index - 1;
++ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83792d_data *data = i2c_get_clientdata(client);
+- u32 val;
++ u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255) >> 4;
+
+- val = simple_strtoul(buf, NULL, 10);
+- data->pwm[nr] = PWM_TO_REG(val);
++ mutex_lock(&data->update_lock);
++ val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0;
++ data->pwm[nr] = val;
+ w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+@@ -707,9 +706,9 @@ store_pwmenable(struct device *dev, stru
+ }
+
+ static struct sensor_device_attribute sda_pwm[] = {
+- SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+- SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+- SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
++ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
++ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
++ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+ };
+ static struct sensor_device_attribute sda_pwm_enable[] = {
+ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+@@ -728,7 +727,7 @@ show_pwm_mode(struct device *dev, struct
+ 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]);
++ return sprintf(buf, "%d\n", data->pwm[nr] >> 7);
+ }
+
+ static ssize_t
+@@ -736,29 +735,35 @@ store_pwm_mode(struct device *dev, struc
+ const char *buf, size_t count)
+ {
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+- int nr = sensor_attr->index - 1;
++ int nr = sensor_attr->index;
+ 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);
++ if (val != 0 && val != 1)
++ return -EINVAL;
++
++ mutex_lock(&data->update_lock);
++ data->pwm[nr] = w83792d_read_value(client, W83792D_REG_PWM[nr]);
++ if (val) { /* PWM mode */
++ data->pwm[nr] |= 0x80;
++ } else { /* DC mode */
++ data->pwm[nr] &= 0x7f;
++ }
++ w83792d_write_value(client, W83792D_REG_PWM[nr], data->pwm[nr]);
++ mutex_unlock(&data->update_lock);
+
+ return count;
+ }
+
+ static struct sensor_device_attribute sda_pwm_mode[] = {
+ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 1),
++ show_pwm_mode, store_pwm_mode, 0),
+ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 2),
++ show_pwm_mode, store_pwm_mode, 1),
+ SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+- show_pwm_mode, store_pwm_mode, 3),
++ show_pwm_mode, store_pwm_mode, 2),
+ };
+
+
+@@ -1373,7 +1378,7 @@ static struct w83792d_data *w83792d_upda
+ 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;
++ u8 reg_array_tmp[4], reg_tmp;
+
+ mutex_lock(&data->update_lock);
+
+@@ -1402,10 +1407,8 @@ static struct w83792d_data *w83792d_upda
+ 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,
++ data->pwm[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;
+ }
+
+ reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG);
+@@ -1513,7 +1516,6 @@ static void w83792d_print_debug(struct w
+ 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++) {
diff --git a/i2c/i2c-Kconfig-suggest-N-for-rare-devices.patch b/i2c/i2c-Kconfig-suggest-N-for-rare-devices.patch
new file mode 100644
index 0000000000000..b129beaf081fb
--- /dev/null
+++ b/i2c/i2c-Kconfig-suggest-N-for-rare-devices.patch
@@ -0,0 +1,88 @@
+From khali@linux-fr.org Sun Jun 4 11:00:01 2006
+Date: Sun, 4 Jun 2006 19:59:57 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Subject: i2c: Suggest N for rare devices in Kconfig
+Message-Id: <20060604195957.ff0438f5.khali@linux-fr.org>
+Content-Disposition: inline; filename=i2c-Kconfig-suggest-N-for-rare-devices.patch
+
+Improve the Kconfig help text of the follwing i2c drivers:
+* busses/i2c-pca-isa.c
+* chips/pcf8574.c
+* chips/pcf8591.c
+These are hard to detect and building them into the kernel
+results in long delays at boot.
+
+March 2006, thread "I2C_PCA_ISA causes boot delays"
+http://marc.theaimsgroup.com/?l=linux-kernel&m=114360399415744&w=2
+
+April 2006, thread "i2c-related 1-minute hang during bootup"
+http://marc.theaimsgroup.com/?l=linux-kernel&m=114640992330721&w=2
+
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/i2c/busses/Kconfig | 6 ++++++
+ drivers/i2c/chips/Kconfig | 8 ++++++++
+ 2 files changed, 14 insertions(+)
+
+--- gregkh-2.6.orig/drivers/i2c/busses/Kconfig
++++ gregkh-2.6/drivers/i2c/busses/Kconfig
+@@ -503,6 +503,7 @@ config I2C_PCA_ISA
+ tristate "PCA9564 on an ISA bus"
+ depends on I2C
+ select I2C_ALGOPCA
++ default n
+ help
+ This driver supports ISA boards using the Philips PCA 9564
+ Parallel bus to I2C bus controller
+@@ -510,6 +511,11 @@ config I2C_PCA_ISA
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-isa.
+
++ This device is almost undetectable and using this driver on a
++ system which doesn't have this device will result in long
++ delays when I2C/SMBus chip drivers are loaded (e.g. at boot
++ time). If unsure, say N.
++
+ config I2C_MV64XXX
+ tristate "Marvell mv64xxx I2C Controller"
+ depends on I2C && MV64X60 && EXPERIMENTAL
+--- gregkh-2.6.orig/drivers/i2c/chips/Kconfig
++++ gregkh-2.6/drivers/i2c/chips/Kconfig
+@@ -39,6 +39,7 @@ config SENSORS_EEPROM
+ config SENSORS_PCF8574
+ tristate "Philips PCF8574 and PCF8574A"
+ depends on I2C && EXPERIMENTAL
++ default n
+ help
+ If you say yes here you get support for Philips PCF8574 and
+ PCF8574A chips.
+@@ -46,6 +47,9 @@ config SENSORS_PCF8574
+ This driver can also be built as a module. If so, the module
+ will be called pcf8574.
+
++ These devices are hard to detect and rarely found on mainstream
++ hardware. If unsure, say N.
++
+ config SENSORS_PCA9539
+ tristate "Philips PCA9539 16-bit I/O port"
+ depends on I2C && EXPERIMENTAL
+@@ -59,12 +63,16 @@ config SENSORS_PCA9539
+ config SENSORS_PCF8591
+ tristate "Philips PCF8591"
+ depends on I2C && EXPERIMENTAL
++ default n
+ help
+ If you say yes here you get support for Philips PCF8591 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called pcf8591.
+
++ These devices are hard to detect and rarely found on mainstream
++ hardware. If unsure, say N.
++
+ config ISP1301_OMAP
+ tristate "Philips ISP1301 with OMAP OTG"
+ depends on I2C && ARCH_OMAP_OTG
diff --git a/i2c/i2c-opencores-new-driver.patch b/i2c/i2c-opencores-new-driver.patch
new file mode 100644
index 0000000000000..b78d687bac51e
--- /dev/null
+++ b/i2c/i2c-opencores-new-driver.patch
@@ -0,0 +1,479 @@
+From khali@linux-fr.org Sun Jun 4 11:01:11 2006
+Date: Sun, 4 Jun 2006 20:01:08 +0200
+From: Jean Delvare <khali@linux-fr.org>
+To: Greg KH <greg@kroah.com>
+Cc: Peter Korsgaard <jacmet@sunsite.dk>
+Subject: i2c: New bus driver for the OpenCores I2C controller
+Message-Id: <20060604200108.d3bca76d.khali@linux-fr.org>
+Content-Disposition: inline; filename=i2c-opencores-new-driver.patch
+
+From: Peter Korsgaard <jacmet@sunsite.dk>
+
+The following patch adds support for the OpenCores I2C controller IP
+core (See http://www.opencores.org/projects.cgi/web/i2c/overview).
+
+Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Jean Delvare <khali@linux-fr.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/i2c/busses/i2c-ocores | 51 +++++
+ drivers/i2c/busses/Kconfig | 11 +
+ drivers/i2c/busses/Makefile | 1
+ drivers/i2c/busses/i2c-ocores.c | 343 ++++++++++++++++++++++++++++++++++++
+ include/linux/i2c-ocores.h | 19 +
+ 5 files changed, 425 insertions(+)
+
+--- /dev/null
++++ gregkh-2.6/Documentation/i2c/busses/i2c-ocores
+@@ -0,0 +1,51 @@
++Kernel driver i2c-ocores
++
++Supported adapters:
++ * OpenCores.org I2C controller by Richard Herveille (see datasheet link)
++ Datasheet: http://www.opencores.org/projects.cgi/web/i2c/overview
++
++Author: Peter Korsgaard <jacmet@sunsite.dk>
++
++Description
++-----------
++
++i2c-ocores is an i2c bus driver for the OpenCores.org I2C controller
++IP core by Richard Herveille.
++
++Usage
++-----
++
++i2c-ocores uses the platform bus, so you need to provide a struct
++platform_device with the base address and interrupt number. The
++dev.platform_data of the device should also point to a struct
++ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
++distance between registers and the input clock speed.
++
++E.G. something like:
++
++static struct resource ocores_resources[] = {
++ [0] = {
++ .start = MYI2C_BASEADDR,
++ .end = MYI2C_BASEADDR + 8,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = MYI2C_IRQ,
++ .end = MYI2C_IRQ,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct ocores_i2c_platform_data myi2c_data = {
++ .regstep = 2, /* two bytes between registers */
++ .clock_khz = 50000, /* input clock of 50MHz */
++};
++
++static struct platform_device myi2c = {
++ .name = "ocores-i2c",
++ .dev = {
++ .platform_data = &myi2c_data,
++ },
++ .num_resources = ARRAY_SIZE(ocores_resources),
++ .resource = ocores_resources,
++};
+--- gregkh-2.6.orig/drivers/i2c/busses/Kconfig
++++ gregkh-2.6/drivers/i2c/busses/Kconfig
+@@ -276,6 +276,17 @@ config I2C_NFORCE2
+ This driver can also be built as a module. If so, the module
+ will be called i2c-nforce2.
+
++config I2C_OCORES
++ tristate "OpenCores I2C Controller"
++ depends on I2C && EXPERIMENTAL
++ help
++ If you say yes to this option, support will be included for the
++ OpenCores I2C controller. For details see
++ http://www.opencores.org/projects.cgi/web/i2c/overview
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-ocores.
++
+ config I2C_PARPORT
+ tristate "Parallel port adapter"
+ depends on I2C && PARPORT
+--- gregkh-2.6.orig/drivers/i2c/busses/Makefile
++++ gregkh-2.6/drivers/i2c/busses/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powerm
+ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+ obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+ obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
++obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
+ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
+--- /dev/null
++++ gregkh-2.6/drivers/i2c/busses/i2c-ocores.c
+@@ -0,0 +1,343 @@
++/*
++ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
++ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
++ *
++ * Peter Korsgaard <jacmet@sunsite.dk>
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/wait.h>
++#include <linux/i2c-ocores.h>
++#include <asm/io.h>
++
++struct ocores_i2c {
++ void __iomem *base;
++ int regstep;
++ wait_queue_head_t wait;
++ struct i2c_adapter adap;
++ struct i2c_msg *msg;
++ int pos;
++ int nmsgs;
++ int state; /* see STATE_ */
++};
++
++/* registers */
++#define OCI2C_PRELOW 0
++#define OCI2C_PREHIGH 1
++#define OCI2C_CONTROL 2
++#define OCI2C_DATA 3
++#define OCI2C_CMD 4
++#define OCI2C_STATUS 4
++
++#define OCI2C_CTRL_IEN 0x40
++#define OCI2C_CTRL_EN 0x80
++
++#define OCI2C_CMD_START 0x91
++#define OCI2C_CMD_STOP 0x41
++#define OCI2C_CMD_READ 0x21
++#define OCI2C_CMD_WRITE 0x11
++#define OCI2C_CMD_READ_ACK 0x21
++#define OCI2C_CMD_READ_NACK 0x29
++#define OCI2C_CMD_IACK 0x01
++
++#define OCI2C_STAT_IF 0x01
++#define OCI2C_STAT_TIP 0x02
++#define OCI2C_STAT_ARBLOST 0x20
++#define OCI2C_STAT_BUSY 0x40
++#define OCI2C_STAT_NACK 0x80
++
++#define STATE_DONE 0
++#define STATE_START 1
++#define STATE_WRITE 2
++#define STATE_READ 3
++#define STATE_ERROR 4
++
++static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
++{
++ iowrite8(value, i2c->base + reg * i2c->regstep);
++}
++
++static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
++{
++ return ioread8(i2c->base + reg * i2c->regstep);
++}
++
++static void ocores_process(struct ocores_i2c *i2c)
++{
++ struct i2c_msg *msg = i2c->msg;
++ u8 stat = oc_getreg(i2c, OCI2C_STATUS);
++
++ if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
++ /* stop has been sent */
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
++ wake_up(&i2c->wait);
++ return;
++ }
++
++ /* error? */
++ if (stat & OCI2C_STAT_ARBLOST) {
++ i2c->state = STATE_ERROR;
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
++ return;
++ }
++
++ if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
++ i2c->state =
++ (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
++
++ if (stat & OCI2C_STAT_NACK) {
++ i2c->state = STATE_ERROR;
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
++ return;
++ }
++ } else
++ msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
++
++ /* end of msg? */
++ if (i2c->pos == msg->len) {
++ i2c->nmsgs--;
++ i2c->msg++;
++ i2c->pos = 0;
++ msg = i2c->msg;
++
++ if (i2c->nmsgs) { /* end? */
++ /* send start? */
++ if (!(msg->flags & I2C_M_NOSTART)) {
++ u8 addr = (msg->addr << 1);
++
++ if (msg->flags & I2C_M_RD)
++ addr |= 1;
++
++ i2c->state = STATE_START;
++
++ oc_setreg(i2c, OCI2C_DATA, addr);
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
++ return;
++ } else
++ i2c->state = (msg->flags & I2C_M_RD)
++ ? STATE_READ : STATE_WRITE;
++ } else {
++ i2c->state = STATE_DONE;
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
++ return;
++ }
++ }
++
++ if (i2c->state == STATE_READ) {
++ oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
++ OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
++ } else {
++ oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
++ }
++}
++
++static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct ocores_i2c *i2c = dev_id;
++
++ ocores_process(i2c);
++
++ return IRQ_HANDLED;
++}
++
++static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
++{
++ struct ocores_i2c *i2c = i2c_get_adapdata(adap);
++
++ i2c->msg = msgs;
++ i2c->pos = 0;
++ i2c->nmsgs = num;
++ i2c->state = STATE_START;
++
++ oc_setreg(i2c, OCI2C_DATA,
++ (i2c->msg->addr << 1) |
++ ((i2c->msg->flags & I2C_M_RD) ? 1:0));
++
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
++
++ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
++ (i2c->state == STATE_DONE), HZ))
++ return (i2c->state == STATE_DONE) ? num : -EIO;
++ else
++ return -ETIMEDOUT;
++}
++
++static void ocores_init(struct ocores_i2c *i2c,
++ struct ocores_i2c_platform_data *pdata)
++{
++ int prescale;
++ u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
++
++ /* make sure the device is disabled */
++ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
++
++ prescale = (pdata->clock_khz / (5*100)) - 1;
++ oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
++ oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
++
++ /* Init the device */
++ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
++ oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
++}
++
++
++static u32 ocores_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm ocores_algorithm = {
++ .master_xfer = ocores_xfer,
++ .functionality = ocores_func,
++};
++
++static struct i2c_adapter ocores_adapter = {
++ .owner = THIS_MODULE,
++ .name = "i2c-ocores",
++ .class = I2C_CLASS_HWMON,
++ .algo = &ocores_algorithm,
++ .timeout = 2,
++ .retries = 1,
++};
++
++
++static int __devinit ocores_i2c_probe(struct platform_device *pdev)
++{
++ struct ocores_i2c *i2c;
++ struct ocores_i2c_platform_data *pdata;
++ struct resource *res, *res2;
++ int ret;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENODEV;
++
++ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res2)
++ return -ENODEV;
++
++ pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data;
++ if (!pdata)
++ return -ENODEV;
++
++ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
++ if (!i2c)
++ return -ENOMEM;
++
++ if (!request_mem_region(res->start, res->end - res->start + 1,
++ pdev->name)) {
++ dev_err(&pdev->dev, "Memory region busy\n");
++ ret = -EBUSY;
++ goto request_mem_failed;
++ }
++
++ i2c->base = ioremap(res->start, res->end - res->start + 1);
++ if (!i2c->base) {
++ dev_err(&pdev->dev, "Unable to map registers\n");
++ ret = -EIO;
++ goto map_failed;
++ }
++
++ i2c->regstep = pdata->regstep;
++ ocores_init(i2c, pdata);
++
++ init_waitqueue_head(&i2c->wait);
++ ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c);
++ if (ret) {
++ dev_err(&pdev->dev, "Cannot claim IRQ\n");
++ goto request_irq_failed;
++ }
++
++ /* hook up driver to tree */
++ platform_set_drvdata(pdev, i2c);
++ i2c->adap = ocores_adapter;
++ i2c_set_adapdata(&i2c->adap, i2c);
++ i2c->adap.dev.parent = &pdev->dev;
++
++ /* add i2c adapter to i2c tree */
++ ret = i2c_add_adapter(&i2c->adap);
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to add adapter\n");
++ goto add_adapter_failed;
++ }
++
++ return 0;
++
++add_adapter_failed:
++ free_irq(res2->start, i2c);
++request_irq_failed:
++ iounmap(i2c->base);
++map_failed:
++ release_mem_region(res->start, res->end - res->start + 1);
++request_mem_failed:
++ kfree(i2c);
++
++ return ret;
++}
++
++static int __devexit ocores_i2c_remove(struct platform_device* pdev)
++{
++ struct ocores_i2c *i2c = platform_get_drvdata(pdev);
++ struct resource *res;
++
++ /* disable i2c logic */
++ oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
++ & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
++
++ /* remove adapter & data */
++ i2c_del_adapter(&i2c->adap);
++ platform_set_drvdata(pdev, NULL);
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (res)
++ free_irq(res->start, i2c);
++
++ iounmap(i2c->base);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res)
++ release_mem_region(res->start, res->end - res->start + 1);
++
++ kfree(i2c);
++
++ return 0;
++}
++
++static struct platform_driver ocores_i2c_driver = {
++ .probe = ocores_i2c_probe,
++ .remove = __devexit_p(ocores_i2c_remove),
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "ocores-i2c",
++ },
++};
++
++static int __init ocores_i2c_init(void)
++{
++ return platform_driver_register(&ocores_i2c_driver);
++}
++
++static void __exit ocores_i2c_exit(void)
++{
++ platform_driver_unregister(&ocores_i2c_driver);
++}
++
++module_init(ocores_i2c_init);
++module_exit(ocores_i2c_exit);
++
++MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
++MODULE_DESCRIPTION("OpenCores I2C bus driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ gregkh-2.6/include/linux/i2c-ocores.h
+@@ -0,0 +1,19 @@
++/*
++ * i2c-ocores.h - definitions for the i2c-ocores interface
++ *
++ * Peter Korsgaard <jacmet@sunsite.dk>
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ */
++
++#ifndef _LINUX_I2C_OCORES_H
++#define _LINUX_I2C_OCORES_H
++
++struct ocores_i2c_platform_data {
++ u32 regstep; /* distance between registers */
++ u32 clock_khz; /* input clock in kHz */
++};
++
++#endif /* _LINUX_I2C_OCORES_H */