Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 19 Feb 2007 21:36:16 +0000 (13:36 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 19 Feb 2007 21:36:16 +0000 (13:36 -0800)
* 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6:
  hwmon/vt1211: Add probing of alternate config index port
  hwmon/f71805f: Fix a race condition
  hwmon/abituguru: Fix unchecked return status
  hwmon: New driver for the Analog Devices ADM1029
  hwmon/w83627ehf: Add support for the W83627DHG chip
  hwmon: Use subsys_initcall
  hwmon/lm70: Make lm70_remove a __devexit function
  hwmon: Cleanup a bogus legacy comment
  hwmon: Simplify the locking model of two drivers
  hwmon: Drop unused mutexes in two drivers
  hwmon/it87: Add PWM base frequency control

21 files changed:
Documentation/hwmon/it87
Documentation/hwmon/sysfs-interface
Documentation/hwmon/w83627ehf
MAINTAINERS
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1029.c [new file with mode: 0644]
drivers/hwmon/f71805f.c
drivers/hwmon/hwmon.c
drivers/hwmon/it87.c
drivers/hwmon/lm70.c
drivers/hwmon/lm78.c
drivers/hwmon/lm85.c
drivers/hwmon/sis5595.c
drivers/hwmon/via686a.c
drivers/hwmon/vt1211.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c

index 74a80992d237c49c13e858313a5c004d351d7e3f..c0528d6f9aceb9e8066533f3821315d1a4c55679 100644 (file)
@@ -135,6 +135,16 @@ Give 0 for unused sensor. Any other value is invalid. To configure this at
 startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor;
 3 = thermal diode)
 
+
+Fan speed control
+-----------------
+
 The fan speed control features are limited to manual PWM mode. Automatic
 "Smart Guardian" mode control handling is not implemented. However
 if you want to go for "manual mode" just write 1 to pwmN_enable.
+
+If you are only able to control the fan speed with very small PWM values,
+try lowering the PWM base frequency (pwm1_freq). Depending on the fan,
+it may give you a somewhat greater control range. The same frequency is
+used to drive all fan outputs, which is why pwm2_freq and pwm3_freq are
+read-only.
index efef3b962cd3eb86f586e811b77ad7b6eadee648..d73d2e8c75344ca86b8e432e4620451d930bdeb7 100644 (file)
@@ -166,16 +166,21 @@ pwm[1-*]  Pulse width modulation fan control.
 
 pwm[1-*]_enable
                Switch PWM on and off.
-               Not always present even if fan*_pwm is.
+               Not always present even if pwmN is.
                0: turn off
                1: turn on in manual mode
                2+: turn on in automatic mode
-               Check individual chip documentation files for automatic mode details.
+               Check individual chip documentation files for automatic mode
+               details.
                RW
 
-pwm[1-*]_mode
-               0: DC mode
-               1: PWM mode
+pwm[1-*]_mode  0: DC mode (direct current)
+               1: PWM mode (pulse-width modulation)
+               RW
+
+pwm[1-*]_freq  Base PWM frequency in Hz.
+               Only possibly available when pwmN_mode is PWM, but not always
+               present even then.
                RW
 
 pwm[1-*]_auto_channels_temp
index 8a15a7408753bc6dda49353966b699992279e4f2..030fac6cec7a21b047780120bef166ff5975734a 100644 (file)
@@ -2,26 +2,29 @@ Kernel driver w83627ehf
 =======================
 
 Supported chips:
-  * Winbond W83627EHF/EHG (ISA access ONLY)
+  * Winbond W83627EHF/EHG/DHG (ISA access ONLY)
     Prefix: 'w83627ehf'
     Addresses scanned: ISA address retrieved from Super I/O registers
-    Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
+    Datasheet:
+        http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
+        DHG datasheet confidential.
 
 Authors:
         Jean Delvare <khali@linux-fr.org>
         Yuan Mu (Winbond)
         Rudolf Marek <r.marek@assembler.cz>
+        David Hubbard <david.c.hubbard@gmail.com>
 
 Description
 -----------
 
-This driver implements support for the Winbond W83627EHF and W83627EHG
-super I/O chips. We will refer to them collectively as Winbond chips.
+This driver implements support for the Winbond W83627EHF, W83627EHG, and
+W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors, alarms with beep warnings (control
-unimplemented), and some automatic fan regulation strategies (plus manual
-fan control mode).
+speed sensors, ten analog voltage sensors (only nine for the 627DHG), alarms
+with beep warnings (control unimplemented), and some automatic fan regulation
+strategies (plus manual fan control mode).
 
 Temperatures are measured in degrees Celsius and measurement resolution is 1
 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
@@ -55,6 +58,9 @@ prog  -> pwm4 (the programmable setting is not supported by the driver)
 /sys files
 ----------
 
+name - this is a standard hwmon device entry. For the W83627EHF and W83627EHG,
+       it is set to "w83627ehf" and for the W83627DHG it is set to "w83627dhg"
+
 pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
           0 (stop) to 255 (full)
 
@@ -83,3 +89,37 @@ pwm[1-4]_stop_time  - how many milliseconds [ms] must elapse to switch
 
 Note: last two functions are influenced by other control bits, not yet exported
       by the driver, so a change might not have any effect.
+
+Implementation Details
+----------------------
+
+Future driver development should bear in mind that the following registers have
+different functions on the 627EHF and the 627DHG. Some registers also have
+different power-on default values, but BIOS should already be loading
+appropriate defaults. Note that bank selection must be performed as is currently
+done in the driver for all register addresses.
+
+0x49:  only on DHG, selects temperature source for AUX fan, CPU fan0
+0x4a:  not completely documented for the EHF and the DHG documentation assigns
+       different behavior to bits 7 and 6, including extending the temperature
+       input selection to SmartFan I, not just SmartFan III. Testing on the EHF
+       will reveal whether they are compatible or not.
+
+0x58:  Chip ID: 0xa1=EHF 0xc1=DHG
+0x5e:  only on DHG, has bits to enable "current mode" temperature detection and
+       critical temperature protection
+0x45b: only on EHF, bit 3, vin4 alarm (EHF supports 10 inputs, only 9 on DHG)
+0x552: only on EHF, vin4
+0x558: only on EHF, vin4 high limit
+0x559: only on EHF, vin4 low limit
+0x6b:  only on DHG, SYS fan critical temperature
+0x6c:  only on DHG, CPU fan0 critical temperature
+0x6d:  only on DHG, AUX fan critical temperature
+0x6e:  only on DHG, CPU fan1 critical temperature
+
+0x50-0x55 and 0x650-0x657 are marked "Test Register" for the EHF, but "Reserved
+       Register" for the DHG
+
+The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and
+the ICH8 southbridge gets that data via PECI from the DHG, so that the
+southbridge drives the fans. And the DHG supports SST, a one-wire serial bus.
index 270c6b006b91560fad13afe140ed5aabfdcacd76..6261597a1bce3037b386628760f0821189c498a5 100644 (file)
@@ -275,6 +275,12 @@ M: khali@linux-fr.org
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 
+ADM1029 HARDWARE MONITOR DRIVER
+P:     Corentin Labbe
+M:     corentin.labbe@geomatys.fr
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 ADT746X FAN DRIVER
 P:     Colin Leroy
 M:     colin@colino.net
index 891ef6d0b1bf970d2a1fd2e6aad9fa43ba16df6d..c3d4856fb61805cbd9217e3a0bd84ee7cc4ceb24 100644 (file)
@@ -73,6 +73,17 @@ config SENSORS_ADM1026
          This driver can also be built as a module.  If so, the module
          will be called adm1026.
 
+config SENSORS_ADM1029
+       tristate "Analog Devices ADM1029"
+       depends on HWMON && I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Analog Devices ADM1029
+         sensor chip.
+         Very rare chip, please let us know you use it.
+
+         This driver can also be built as a module.  If so, the module
+         will be called adm1029.
+
 config SENSORS_ADM1031
        tristate "Analog Devices ADM1031 and compatibles"
        depends on HWMON && I2C && EXPERIMENTAL
index 31661124271ee58d57adce2b33607669142feade..4165c27a2f255bdd1a0b33e62780e15bb2fa21e8 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU)       += abituguru.o
 obj-$(CONFIG_SENSORS_ADM1021)  += adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)  += adm1025.o
 obj-$(CONFIG_SENSORS_ADM1026)  += adm1026.o
+obj-$(CONFIG_SENSORS_ADM1029)  += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
 obj-$(CONFIG_SENSORS_AMS)      += ams/
index b1dc63e4ac7b32342f19d75ead8a71c82d7d699b..bede4d990ea67330546e7b897ae51bf434f55341 100644 (file)
@@ -1267,30 +1267,42 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
        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)) {
-               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);
+               if (device_create_file(&pdev->dev,
+                               &data->sysfs_attr[i].dev_attr))
+                       goto abituguru_probe_error;
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
-               device_create_file(&pdev->dev,
-                       &abituguru_sysfs_attr[i].dev_attr);
+               if (device_create_file(&pdev->dev,
+                               &abituguru_sysfs_attr[i].dev_attr))
+                       goto abituguru_probe_error;
 
-       return 0;
+       data->class_dev = hwmon_device_register(&pdev->dev);
+       if (!IS_ERR(data->class_dev))
+               return 0; /* success */
 
+       res = PTR_ERR(data->class_dev);
 abituguru_probe_error:
+       for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+               device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+       for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+               device_remove_file(&pdev->dev,
+                       &abituguru_sysfs_attr[i].dev_attr);
        kfree(data);
        return res;
 }
 
 static int __devexit abituguru_remove(struct platform_device *pdev)
 {
+       int i;
        struct abituguru_data *data = platform_get_drvdata(pdev);
 
        platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->class_dev);
+       for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+               device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+       for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+               device_remove_file(&pdev->dev,
+                       &abituguru_sysfs_attr[i].dev_attr);
        kfree(data);
 
        return 0;
index b4618b2705f76ae1805ab5dd5f24c2c76833d241..ba80cd3258c69fe63f0277726cf37bec2f653f0f 100644 (file)
@@ -261,7 +261,6 @@ struct pwm_data {
 struct adm1026_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct mutex lock;
        enum chips type;
 
        struct mutex update_lock;
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
new file mode 100644 (file)
index 0000000..73ce31b
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ *
+ * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
+ *
+ * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org>
+ *
+ * Give only processor, motherboard temperatures and fan tachs
+ * Very rare chip please let me know if you use it
+ *
+ * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ */
+
+static unsigned short normal_i2c[] = {
+       0x28, 0x29, 0x2a,
+       0x2b, 0x2c, 0x2d,
+       0x2e, 0x2f, I2C_CLIENT_END
+};
+
+/*
+ * Insmod parameters
+ */
+
+I2C_CLIENT_INSMOD_1(adm1029);
+
+/*
+ * The ADM1029 registers
+ * Manufacturer ID is 0x41 for Analog Devices
+ */
+
+#define ADM1029_REG_MAN_ID                     0x0D
+#define ADM1029_REG_CHIP_ID                    0x0E
+#define ADM1029_REG_CONFIG                     0x01
+#define ADM1029_REG_NB_FAN_SUPPORT             0x02
+
+#define ADM1029_REG_TEMP_DEVICES_INSTALLED     0x06
+
+#define ADM1029_REG_LOCAL_TEMP                 0xA0
+#define ADM1029_REG_REMOTE1_TEMP               0xA1
+#define ADM1029_REG_REMOTE2_TEMP               0xA2
+
+#define ADM1029_REG_LOCAL_TEMP_HIGH            0x90
+#define ADM1029_REG_REMOTE1_TEMP_HIGH          0x91
+#define ADM1029_REG_REMOTE2_TEMP_HIGH          0x92
+
+#define ADM1029_REG_LOCAL_TEMP_LOW             0x98
+#define ADM1029_REG_REMOTE1_TEMP_LOW           0x99
+#define ADM1029_REG_REMOTE2_TEMP_LOW           0x9A
+
+#define ADM1029_REG_FAN1                       0x70
+#define ADM1029_REG_FAN2                       0x71
+
+#define ADM1029_REG_FAN1_MIN                   0x78
+#define ADM1029_REG_FAN2_MIN                   0x79
+
+#define ADM1029_REG_FAN1_CONFIG                        0x68
+#define ADM1029_REG_FAN2_CONFIG                        0x69
+
+#define TEMP_FROM_REG(val)     ((val) * 1000)
+
+#define DIV_FROM_REG(val)      ( 1 << (((val) >> 6) - 1))
+
+/* Registers to be checked by adm1029_update_device() */
+static const u8 ADM1029_REG_TEMP[] = {
+       ADM1029_REG_LOCAL_TEMP,
+       ADM1029_REG_REMOTE1_TEMP,
+       ADM1029_REG_REMOTE2_TEMP,
+       ADM1029_REG_LOCAL_TEMP_HIGH,
+       ADM1029_REG_REMOTE1_TEMP_HIGH,
+       ADM1029_REG_REMOTE2_TEMP_HIGH,
+       ADM1029_REG_LOCAL_TEMP_LOW,
+       ADM1029_REG_REMOTE1_TEMP_LOW,
+       ADM1029_REG_REMOTE2_TEMP_LOW,
+};
+
+static const u8 ADM1029_REG_FAN[] = {
+       ADM1029_REG_FAN1,
+       ADM1029_REG_FAN2,
+       ADM1029_REG_FAN1_MIN,
+       ADM1029_REG_FAN2_MIN,
+};
+
+static const u8 ADM1029_REG_FAN_DIV[] = {
+       ADM1029_REG_FAN1_CONFIG,
+       ADM1029_REG_FAN2_CONFIG,
+};
+
+/*
+ * Functions declaration
+ */
+
+static int adm1029_attach_adapter(struct i2c_adapter *adapter);
+static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm1029_detach_client(struct i2c_client *client);
+static struct adm1029_data *adm1029_update_device(struct device *dev);
+static int adm1029_init_client(struct i2c_client *client);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver adm1029_driver = {
+       .driver = {
+               .name = "adm1029",
+       },
+       .attach_adapter = adm1029_attach_adapter,
+       .detach_client = adm1029_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct adm1029_data {
+       struct i2c_client client;
+       struct class_device *class_dev;
+       struct mutex update_lock;
+       char valid;             /* zero until following fields are valid */
+       unsigned long last_updated;     /* in jiffies */
+
+       /* registers values, signed for temperature, unsigned for other stuff */
+       s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];
+       u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];
+       u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adm1029_data *data = adm1029_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adm1029_data *data = adm1029_update_device(dev);
+       u16 val;
+       if (data->fan[attr->index] == 0 || data->fan_div[attr->index] == 0
+           || data->fan[attr->index] == 255) {
+               return sprintf(buf, "0\n");
+       }
+
+       val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
+           / data->fan[attr->index];
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct adm1029_data *data = adm1029_update_device(dev);
+       if (data->fan_div[attr->index] == 0)
+               return sprintf(buf, "0\n");
+       return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+           struct device_attribute *devattr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1029_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       long val = simple_strtol(buf, NULL, 10);
+       u8 reg;
+
+       mutex_lock(&data->update_lock);
+
+       /*Read actual config */
+       reg = i2c_smbus_read_byte_data(client,
+                                      ADM1029_REG_FAN_DIV[attr->index]);
+
+       switch (val) {
+       case 1:
+               val = 1;
+               break;
+       case 2:
+               val = 2;
+               break;
+       case 4:
+               val = 3;
+               break;
+       default:
+               mutex_unlock(&data->update_lock);
+               dev_err(&client->dev, "fan_div value %ld not "
+                       "supported. Choose one of 1, 2 or 4!\n", val);
+               return -EINVAL;
+       }
+       /* Update the value */
+       reg = (reg & 0x3F) | (val << 6);
+
+       /* Write value */
+       i2c_smbus_write_byte_data(client,
+                                 ADM1029_REG_FAN_DIV[attr->index], reg);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/*
+Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others
+                       S_IWUSR stand for Is Writable by User
+*/
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+                         show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+                         show_fan_div, set_fan_div, 1);
+
+static struct attribute *adm1029_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_div.dev_attr.attr,
+       &sensor_dev_attr_fan2_div.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adm1029_group = {
+       .attrs = adm1029_attributes,
+};
+
+/*
+ * Real code
+ */
+
+static int adm1029_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_probe(adapter, &addr_data, adm1029_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+
+static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct adm1029_data *data;
+       int err = 0;
+       const char *name = "";
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       client = &data->client;
+       i2c_set_clientdata(client, data);
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &adm1029_driver;
+
+       /* Now we do the detection and identification. A negative kind
+        * means that the driver was loaded with no force parameter
+        * (default), so we must both detect and identify the chip
+        * (actually there is only one possible kind of chip for now, adm1029).
+        * A zero kind means that the driver was loaded with the force
+        * parameter, the detection step shall be skipped. A positive kind
+        * means that the driver was loaded with the force parameter and a
+        * given kind of chip is requested, so both the detection and the
+        * identification steps are skipped. */
+
+       /* Default to an adm1029 if forced */
+       if (kind == 0)
+               kind = adm1029;
+
+       /* ADM1029 doesn't have CHIP ID, check just MAN ID
+        * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
+        * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
+        * documented
+        */
+
+       if (kind <= 0) {        /* identification */
+               u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
+
+               man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
+               chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
+               temp_devices_installed = i2c_smbus_read_byte_data(client,
+                                       ADM1029_REG_TEMP_DEVICES_INSTALLED);
+               nb_fan_support = i2c_smbus_read_byte_data(client,
+                                               ADM1029_REG_NB_FAN_SUPPORT);
+               /* 0x41 is Analog Devices */
+               if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01
+                   && nb_fan_support == 0x03) {
+                       if ((chip_id & 0xF0) == 0x00) {
+                               kind = adm1029;
+                       } else {
+                               /* There are no "official" CHIP ID, so actually
+                                * we use Major/Minor revision for that */
+                               printk(KERN_INFO
+                                      "adm1029: Unknown major revision %x, "
+                                      "please let us know\n", chip_id);
+                       }
+               }
+
+               if (kind <= 0) {        /* identification failed */
+                       pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
+                                "chip_id=0x%02X)\n", man_id, chip_id);
+                       goto exit_free;
+               }
+       }
+
+       if (kind == adm1029) {
+               name = "adm1029";
+       }
+
+       /* We can fill in the remaining client fields */
+       strlcpy(client->name, name, I2C_NAME_SIZE);
+       mutex_init(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(client)))
+               goto exit_free;
+
+       /*
+        * Initialize the ADM1029 chip
+        * Check config register
+        */
+       if (adm1029_init_client(client) == 0)
+               goto exit_detach;
+
+       /* Register sysfs hooks */
+       if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
+               goto exit_detach;
+
+       data->class_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->class_dev)) {
+               err = PTR_ERR(data->class_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+ exit_remove_files:
+       sysfs_remove_group(&client->dev.kobj, &adm1029_group);
+ exit_detach:
+       i2c_detach_client(client);
+ exit_free:
+       kfree(data);
+ exit:
+       return err;
+}
+
+static int adm1029_init_client(struct i2c_client *client)
+{
+       u8 config;
+       config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+       if ((config & 0x10) == 0) {
+               i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
+                                         config | 0x10);
+       }
+       /* recheck config */
+       config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+       if ((config & 0x10) == 0) {
+               dev_err(&client->dev, "Initialization failed!\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int adm1029_detach_client(struct i2c_client *client)
+{
+       struct adm1029_data *data = i2c_get_clientdata(client);
+       int err;
+
+       hwmon_device_unregister(data->class_dev);
+       sysfs_remove_group(&client->dev.kobj, &adm1029_group);
+
+       if ((err = i2c_detach_client(client)))
+               return err;
+
+       kfree(data);
+       return 0;
+}
+
+/*
+function that update the status of the chips (temperature for exemple)
+*/
+static struct adm1029_data *adm1029_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1029_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+       /*
+        * Use the "cache" Luke, don't recheck values
+        * if there are already checked not a long time later
+        */
+       if (time_after(jiffies, data->last_updated + HZ * 2)
+        || !data->valid) {
+               int nr;
+
+               dev_dbg(&client->dev, "Updating adm1029 data\n");
+
+               for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
+                       data->temp[nr] =
+                           i2c_smbus_read_byte_data(client,
+                                                    ADM1029_REG_TEMP[nr]);
+               }
+               for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
+                       data->fan[nr] =
+                           i2c_smbus_read_byte_data(client,
+                                                    ADM1029_REG_FAN[nr]);
+               }
+               for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
+                       data->fan_div[nr] =
+                           i2c_smbus_read_byte_data(client,
+                                                    ADM1029_REG_FAN_DIV[nr]);
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/*
+       Common module stuff
+*/
+static int __init sensors_adm1029_init(void)
+{
+
+       return i2c_add_driver(&adm1029_driver);
+}
+
+static void __exit sensors_adm1029_exit(void)
+{
+
+       i2c_del_driver(&adm1029_driver);
+}
+
+MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
+MODULE_DESCRIPTION("adm1029 driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(sensors_adm1029_init);
+module_exit(sensors_adm1029_exit);
index a272cae8f60ef212d179a767daac10d7fa823593..7c2973487122cd139b22081225cbcbefefa28bae 100644 (file)
@@ -146,7 +146,6 @@ superio_exit(int base)
 struct f71805f_data {
        unsigned short addr;
        const char *name;
-       struct mutex lock;
        struct class_device *class_dev;
 
        struct mutex update_lock;
@@ -271,50 +270,42 @@ static inline u8 temp_to_reg(long val)
  * Device I/O access
  */
 
+/* Must be called with data->update_lock held, except during initialization */
 static u8 f71805f_read8(struct f71805f_data *data, u8 reg)
 {
-       u8 val;
-
-       mutex_lock(&data->lock);
        outb(reg, data->addr + ADDR_REG_OFFSET);
-       val = inb(data->addr + DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
-
-       return val;
+       return inb(data->addr + DATA_REG_OFFSET);
 }
 
+/* Must be called with data->update_lock held, except during initialization */
 static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val)
 {
-       mutex_lock(&data->lock);
        outb(reg, data->addr + ADDR_REG_OFFSET);
        outb(val, data->addr + DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
 }
 
 /* It is important to read the MSB first, because doing so latches the
-   value of the LSB, so we are sure both bytes belong to the same value. */
+   value of the LSB, so we are sure both bytes belong to the same value.
+   Must be called with data->update_lock held, except during initialization */
 static u16 f71805f_read16(struct f71805f_data *data, u8 reg)
 {
        u16 val;
 
-       mutex_lock(&data->lock);
        outb(reg, data->addr + ADDR_REG_OFFSET);
        val = inb(data->addr + DATA_REG_OFFSET) << 8;
        outb(++reg, data->addr + ADDR_REG_OFFSET);
        val |= inb(data->addr + DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
 
        return val;
 }
 
+/* Must be called with data->update_lock held, except during initialization */
 static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
 {
-       mutex_lock(&data->lock);
        outb(reg, data->addr + ADDR_REG_OFFSET);
        outb(val >> 8, data->addr + DATA_REG_OFFSET);
        outb(++reg, data->addr + ADDR_REG_OFFSET);
        outb(val & 0xff, data->addr + DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
 }
 
 static struct f71805f_data *f71805f_update_device(struct device *dev)
@@ -1150,7 +1141,6 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        data->addr = res->start;
-       mutex_init(&data->lock);
        data->name = names[sio_data->kind];
        mutex_init(&data->update_lock);
 
@@ -1300,14 +1290,11 @@ static int __init f71805f_device_add(unsigned short address,
        if (err) {
                printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
                       err);
-               goto exit_kfree_data;
+               goto exit_device_put;
        }
 
        return 0;
 
-exit_kfree_data:
-       kfree(pdev->dev.platform_data);
-       pdev->dev.platform_data = NULL;
 exit_device_put:
        platform_device_put(pdev);
 exit:
@@ -1400,10 +1387,7 @@ exit:
 
 static void __exit f71805f_exit(void)
 {
-       kfree(pdev->dev.platform_data);
-       pdev->dev.platform_data = NULL;
        platform_device_unregister(pdev);
-
        platform_driver_unregister(&f71805f_driver);
 }
 
index 106fa01cdb6069717c61ee6a596e94d1ad38bf98..affcc00764d3d207cf2225240802a5255b2a7d9c 100644 (file)
@@ -101,7 +101,7 @@ static void __exit hwmon_exit(void)
        class_destroy(hwmon_class);
 }
 
-module_init(hwmon_init);
+subsys_initcall(hwmon_init);
 module_exit(hwmon_exit);
 
 EXPORT_SYMBOL_GPL(hwmon_device_register);
index 1ed8b7e2c35df01e57dfab60aab6c0dc8825c37e..62afc63708a5c85dec58aae278b2f2047c476e3e 100644 (file)
@@ -202,15 +202,23 @@ static int DIV_TO_REG(int val)
 }
 #define DIV_FROM_REG(val) (1 << (val))
 
+static const unsigned int pwm_freq[8] = {
+       48000000 / 128,
+       24000000 / 128,
+       12000000 / 128,
+       8000000 / 128,
+       6000000 / 128,
+       3000000 / 128,
+       1500000 / 128,
+       750000 / 128,
+};
+
 
-/* For each registered IT87, we need to keep some data in memory. That
-   data is pointed to by it87_list[NR]->data. The structure itself is
-   dynamically allocated, at the same time when a new it87 client is
-   allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct it87_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct mutex lock;
        enum chips type;
 
        struct mutex update_lock;
@@ -232,6 +240,7 @@ struct it87_data {
        u8 vrm;
        u32 alarms;             /* Register encoding, combined */
        u8 fan_main_ctrl;       /* Register value */
+       u8 fan_ctl;             /* Register value */
        u8 manual_pwm_ctl[3];   /* manual PWM value set by user */
 };
 
@@ -519,6 +528,14 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
        struct it87_data *data = it87_update_device(dev);
        return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
 }
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct it87_data *data = it87_update_device(dev);
+       int index = (data->fan_ctl >> 4) & 0x07;
+
+       return sprintf(buf, "%u\n", pwm_freq[index]);
+}
 static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
@@ -528,9 +545,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        struct i2c_client *client = to_i2c_client(dev);
        struct it87_data *data = i2c_get_clientdata(client);
        int val = simple_strtol(buf, NULL, 10);
-       u8 reg = it87_read_value(client, IT87_REG_FAN_DIV);
+       u8 reg;
 
        mutex_lock(&data->update_lock);
+       reg = it87_read_value(client, IT87_REG_FAN_DIV);
        switch (nr) {
        case 0: data->fan_div[nr] = reg & 0x07; break;
        case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -639,6 +657,28 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
        mutex_unlock(&data->update_lock);
        return count;
 }
+static ssize_t set_pwm_freq(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct it87_data *data = i2c_get_clientdata(client);
+       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int i;
+
+       /* Search for the nearest available frequency */
+       for (i = 0; i < 7; i++) {
+               if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
+                       break;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+       data->fan_ctl |= i << 4;
+       it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
 
 #define show_fan_offset(offset)                                        \
 static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                \
@@ -656,7 +696,10 @@ show_fan_offset(3);
 static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,     \
                show_pwm_enable, set_pwm_enable, offset - 1);           \
 static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,              \
-               show_pwm, set_pwm, offset - 1);
+               show_pwm, set_pwm, offset - 1);                         \
+static DEVICE_ATTR(pwm##offset##_freq,                                 \
+               (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO),            \
+               show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL));
 
 show_pwm_offset(1);
 show_pwm_offset(2);
@@ -904,7 +947,6 @@ static int it87_detect(struct i2c_adapter *adapter)
        }
 
        new_client = &data->client;
-       mutex_init(&data->lock);
        i2c_set_clientdata(new_client, data);
        new_client->addr = isa_address;
        new_client->adapter = adapter;
@@ -1021,7 +1063,13 @@ static int it87_detect(struct i2c_adapter *adapter)
                 || (err = device_create_file(&new_client->dev,
                     &sensor_dev_attr_pwm2.dev_attr))
                 || (err = device_create_file(&new_client->dev,
-                    &sensor_dev_attr_pwm3.dev_attr)))
+                    &sensor_dev_attr_pwm3.dev_attr))
+                || (err = device_create_file(&new_client->dev,
+                    &dev_attr_pwm1_freq))
+                || (err = device_create_file(&new_client->dev,
+                    &dev_attr_pwm2_freq))
+                || (err = device_create_file(&new_client->dev,
+                    &dev_attr_pwm3_freq)))
                        goto ERROR4;
        }
 
@@ -1076,33 +1124,22 @@ static int it87_detach_client(struct i2c_client *client)
        return 0;
 }
 
-/* ISA access must be locked explicitly!
+/* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
 static int it87_read_value(struct i2c_client *client, u8 reg)
 {
-       struct it87_data *data = i2c_get_clientdata(client);
-       int res;
-
-       mutex_lock(&data->lock);
        outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-       res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
-
-       return res;
+       return inb_p(client->addr + IT87_DATA_REG_OFFSET);
 }
 
-/* ISA access must be locked explicitly!
+/* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
 static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
 {
-       struct it87_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->lock);
        outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
        outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
-       mutex_unlock(&data->lock);
 }
 
 /* Return 1 if and only if the PWM interface is safe to use */
@@ -1316,6 +1353,7 @@ static struct it87_data *it87_update_device(struct device *dev)
                        (it87_read_value(client, IT87_REG_ALARM2) << 8) |
                        (it87_read_value(client, IT87_REG_ALARM3) << 16);
                data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+               data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
 
                data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
                /* The 8705 does not have VID capability */
index 6ba84731b9cd826639613e46da6e0976ecdddc1e..7eaae3834e157279e926281fd1ec2270c7666f12 100644 (file)
@@ -126,7 +126,7 @@ out_dev_reg_failed:
        return status;
 }
 
-static int __exit lm70_remove(struct spi_device *spi)
+static int __devexit lm70_remove(struct spi_device *spi)
 {
        struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
 
index 73bc2ffc598d2cabf66664f34b43b9f9dbb2d9ce..886786c33916d8960757251d4bdf5fd662a5d6dd 100644 (file)
@@ -125,10 +125,8 @@ static inline int TEMP_FROM_REG(s8 val)
    bad. Quite a lot of bookkeeping is done. A real driver can often cut
    some corners. */
 
-/* For each registered LM78, we need to keep some data in memory. That
-   data is pointed to by lm78_list[NR]->data. The structure itself is
-   dynamically allocated, at the same time when a new lm78 client is
-   allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct lm78_data {
        struct i2c_client client;
        struct class_device *class_dev;
index 2c3293cf69d10303a3a17bde4fb06471a023cefa..20a8c648280d5c64cfe94da9f4de860053ff183d 100644 (file)
@@ -298,11 +298,6 @@ static int ZONE_TO_REG( int zone )
 #define LM85_DATA_INTERVAL  (HZ + HZ / 2)
 #define LM85_CONFIG_INTERVAL  (1 * 60 * HZ)
 
-/* For each registered LM85, we need to keep some data in memory. That
-   data is pointed to by lm85_list[NR]->data. The structure itself is
-   dynamically allocated, at the same time when a new lm85 client is
-   allocated. */
-
 /* LM85 can automatically adjust fan speeds based on temperature
  * This structure encapsulates an entire Zone config.  There are
  * three zones (one for each temperature input) on the lm85
@@ -329,10 +324,11 @@ struct lm85_autofan {
        u8 min_off;     /* Min PWM or OFF below "limit", flag */
 };
 
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct lm85_data {
        struct i2c_client client;
        struct class_device *class_dev;
-       struct mutex lock;
        enum chips type;
 
        struct mutex update_lock;
index 95a4b5d9eaf29820cdba79472de2f97ea482f269..3f400263fc0f2e861b88614634e86b23264a898c 100644 (file)
@@ -162,10 +162,8 @@ static inline u8 DIV_TO_REG(int val)
 }
 #define DIV_FROM_REG(val) (1 << (val))
 
-/* For the SIS5595, we need to keep some data in memory. That
-   data is pointed to by sis5595_list[NR]->data. The structure itself is
-   dynamically allocated, at the time when the new sis5595 client is
-   allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct sis5595_data {
        struct i2c_client client;
        struct class_device *class_dev;
index f8acada0537a7894d6dd318558e3bc71ca1dd546..9a440c8cc5203c3fc4b6ac5646d0d980230284a5 100644 (file)
@@ -292,9 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
 #define DIV_FROM_REG(val) (1 << (val))
 #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
 
-/* For the VIA686A, we need to keep some data in memory.
-   The structure is dynamically allocated, at the same time when a new
-   via686a client is allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct via686a_data {
        struct i2c_client client;
        struct class_device *class_dev;
index 25cc56003d7aeb325277483c53915488540210fc..89c23d6add7be174190cbc90f2cf2f1b25d2be10 100644 (file)
@@ -178,9 +178,10 @@ struct vt1211_data {
  * Super-I/O constants and functions
  * --------------------------------------------------------------------- */
 
-/* Configuration & data index port registers */
-#define SIO_REG_CIP            0x2e
-#define SIO_REG_DIP            0x2f
+/* Configuration index port registers
+ * The vt1211 can live at 2 different addresses so we need to probe both */
+#define SIO_REG_CIP1           0x2e
+#define SIO_REG_CIP2           0x4e
 
 /* Configuration registers */
 #define SIO_VT1211_LDN         0x07    /* logical device number */
@@ -193,33 +194,33 @@ struct vt1211_data {
 /* VT1211 logical device numbers */
 #define SIO_VT1211_LDN_HWMON   0x0b    /* HW monitor */
 
-static inline void superio_outb(int reg, int val)
+static inline void superio_outb(int sio_cip, int reg, int val)
 {
-       outb(reg, SIO_REG_CIP);
-       outb(val, SIO_REG_DIP);
+       outb(reg, sio_cip);
+       outb(val, sio_cip + 1);
 }
 
-static inline int superio_inb(int reg)
+static inline int superio_inb(int sio_cip, int reg)
 {
-       outb(reg, SIO_REG_CIP);
-       return inb(SIO_REG_DIP);
+       outb(reg, sio_cip);
+       return inb(sio_cip + 1);
 }
 
-static inline void superio_select(int ldn)
+static inline void superio_select(int sio_cip, int ldn)
 {
-       outb(SIO_VT1211_LDN, SIO_REG_CIP);
-       outb(ldn, SIO_REG_DIP);
+       outb(SIO_VT1211_LDN, sio_cip);
+       outb(ldn, sio_cip + 1);
 }
 
-static inline void superio_enter(void)
+static inline void superio_enter(int sio_cip)
 {
-       outb(0x87, SIO_REG_CIP);
-       outb(0x87, SIO_REG_CIP);
+       outb(0x87, sio_cip);
+       outb(0x87, sio_cip);
 }
 
-static inline void superio_exit(void)
+static inline void superio_exit(int sio_cip)
 {
-       outb(0xaa, SIO_REG_CIP);
+       outb(0xaa, sio_cip);
 }
 
 /* ---------------------------------------------------------------------
@@ -1263,26 +1264,26 @@ EXIT:
        return err;
 }
 
-static int __init vt1211_find(unsigned short *address)
+static int __init vt1211_find(int sio_cip, unsigned short *address)
 {
        int err = -ENODEV;
 
-       superio_enter();
+       superio_enter(sio_cip);
 
-       if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+       if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) {
                goto EXIT;
        }
 
-       superio_select(SIO_VT1211_LDN_HWMON);
+       superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
 
-       if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
+       if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
                printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
                       "skipping\n");
                goto EXIT;
        }
 
-       *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
-                   (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
+       *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
+                   (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
        if (*address == 0) {
                printk(KERN_WARNING DRVNAME ": Base address is not set, "
                       "skipping\n");
@@ -1291,10 +1292,11 @@ static int __init vt1211_find(unsigned short *address)
 
        err = 0;
        printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
-              "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
+              "revision %u\n", *address,
+              superio_inb(sio_cip, SIO_VT1211_DEVREV));
 
 EXIT:
-       superio_exit();
+       superio_exit(sio_cip);
        return err;
 }
 
@@ -1303,8 +1305,8 @@ static int __init vt1211_init(void)
        int err;
        unsigned short address = 0;
 
-       err = vt1211_find(&address);
-       if (err) {
+       if ((err = vt1211_find(SIO_REG_CIP1, &address)) &&
+           (err = vt1211_find(SIO_REG_CIP2, &address))) {
                goto EXIT;
        }
 
index 212a1558c63b62a0556f469f1370341e9c14b039..da5828f2dfc200d50381498e053bcb2fbdb05642 100644 (file)
 
     Supports the following chips:
 
-    Chip        #vin    #fan    #pwm    #temp   chip_id    man_id
-    w83627ehf   10      5       4       3       0x88,0xa1  0x5ca3
+    Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+    w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
+                                               0x8860 0xa1
+    w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
 */
 
 #include <linux/module.h>
@@ -55,8 +57,18 @@ static unsigned short address;
  * Super-I/O constants and functions
  */
 
+/*
+ * The three following globals are initialized in w83627ehf_find(), before
+ * the i2c-isa device is created. Otherwise, they could be stored in
+ * w83627ehf_data. This is ugly, but necessary, and when the driver is next
+ * updated to become a platform driver, the globals will disappear.
+ */
 static int REG;                /* The register to read/write */
 static int VAL;                /* The value to read/write */
+/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
+ * value is also used in w83627ehf_detect() to export a device name in sysfs
+ * (e.g. w83627ehf or w83627dhg) */
+static int w83627ehf_num_in;
 
 #define W83627EHF_LD_HWM       0x0b
 
@@ -65,8 +77,10 @@ static int VAL;              /* The value to read/write */
 #define SIO_REG_ENABLE         0x30    /* Logical device enable */
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
-#define SIO_W83627EHF_ID       0x8840
-#define SIO_ID_MASK            0xFFC0
+#define SIO_W83627EHF_ID       0x8850
+#define SIO_W83627EHG_ID       0x8860
+#define SIO_W83627DHG_ID       0xa020
+#define SIO_ID_MASK            0xFFF0
 
 static inline void
 superio_outb(int reg, int val)
@@ -115,8 +129,12 @@ superio_exit(void)
 
 #define W83627EHF_REG_BANK             0x4E
 #define W83627EHF_REG_CONFIG           0x40
-#define W83627EHF_REG_CHIP_ID          0x49
-#define W83627EHF_REG_MAN_ID           0x4F
+
+/* Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58 */
 
 static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
 static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
@@ -429,7 +447,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                }
 
                /* Measured voltages and limits */
-               for (i = 0; i < 10; i++) {
+               for (i = 0; i < w83627ehf_num_in; i++) {
                        data->in[i] = w83627ehf_read_value(client,
                                      W83627EHF_REG_IN(i));
                        data->in_min[i] = w83627ehf_read_value(client,
@@ -1121,7 +1139,7 @@ static void w83627ehf_device_remove_files(struct device *dev)
                device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
        for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
                device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
-       for (i = 0; i < 10; i++) {
+       for (i = 0; i < w83627ehf_num_in; i++) {
                device_remove_file(dev, &sda_in_input[i].dev_attr);
                device_remove_file(dev, &sda_in_alarm[i].dev_attr);
                device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1196,7 +1214,11 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
        client->flags = 0;
        dev = &client->dev;
 
-       strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
+       if (w83627ehf_num_in == 9)
+               strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
+       else    /* just say ehf. 627EHG is 627EHF in lead-free packaging. */
+               strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
+
        data->valid = 0;
        mutex_init(&data->update_lock);
 
@@ -1246,7 +1268,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
                                goto exit_remove;
                }
 
-       for (i = 0; i < 10; i++)
+       for (i = 0; i < w83627ehf_num_in; i++)
                if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
                        || (err = device_create_file(dev,
                                &sda_in_alarm[i].dev_attr))
@@ -1340,7 +1362,17 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
 
        val = (superio_inb(SIO_REG_DEVID) << 8)
            | superio_inb(SIO_REG_DEVID + 1);
-       if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
+       switch (val & SIO_ID_MASK) {
+       case SIO_W83627DHG_ID:
+               w83627ehf_num_in = 9;
+               break;
+       case SIO_W83627EHF_ID:
+       case SIO_W83627EHG_ID:
+               w83627ehf_num_in = 10;
+               break;
+       default:
+               printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
+                       val);
                superio_exit();
                return -ENODEV;
        }
index dfdc29c77123a7e0530984f5251f229f000a9f89..d7e240635b3b7b3d370d81db423e48e90b3249a8 100644 (file)
@@ -286,9 +286,8 @@ static inline u8 DIV_TO_REG(long val)
        return ((u8) i);
 }
 
-/* For each registered chip, we need to keep some data in memory. That
-   data is pointed to by w83627hf_list[NR]->data. The structure itself is
-   dynamically allocated, at the same time when a new client is allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct w83627hf_data {
        struct i2c_client client;
        struct class_device *class_dev;
index 1232171c3aad804a97320e0a909bd1fa6ee3d362..a47da3ec5472e61eaab91f5c837df97f708502e0 100644 (file)
@@ -221,14 +221,8 @@ DIV_TO_REG(long val, enum chips type)
    a bit - except if there could be more than one SMBus. Groan. No solution
    for this yet. */
 
-/* This module may seem overly long and complicated. In fact, it is not so
-   bad. Quite a lot of bookkeeping is done. A real driver can often cut
-   some corners. */
-
-/* For each registered W83781D, we need to keep some data in memory. That
-   data is pointed to by w83781d_list[NR]->data. The structure itself is
-   dynamically allocated, at the same time when a new w83781d client is
-   allocated. */
+/* For each registered chip, we need to keep some data in memory.
+   The structure is dynamically allocated. */
 struct w83781d_data {
        struct i2c_client client;
        struct class_device *class_dev;