Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 18:33:46 +0000 (11:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 18:33:46 +0000 (11:33 -0700)
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging: (23 commits)
  hwmon: (lm75) Add support for the Texas Instruments TMP105
  hwmon: (ltc4245) Read only one GPIO pin
  hwmon: (dme1737) Add SCH5127 support
  hwmon: (tmp102) Don't always stop chip at exit
  hwmon: (tmp102) Fix suspend and resume functions
  hwmon: (tmp102) Various fixes
  hwmon: Driver for TI TMP102 temperature sensor
  hwmon: EMC1403 thermal sensor support
  hwmon: (applesmc) Add temperature sensor labels to sysfs interface
  hwmon: (applesmc) Add generic support for MacBook Pro 7
  hwmon: (applesmc) Add generic support for MacBook Pro 6
  hwmon: (applesmc) Add support for MacBook Pro 5,3 and 5,4
  hwmon: (tmp401) Reorganize code to get rid of static forward declarations
  hwmon: (tmp401) Use constants for sysfs file permissions
  hwmon: (adm1031) Allow setting update rate
  hwmon: Add description of the update_rate sysfs attribute
  hwmon: (lm90) Use programmed update rate
  hwmon: (f71882fg) Acquire I/O regions while we're working with them
  hwmon: (f71882fg) Code cleanup
  hwmon: (f71882fg) Use strict_stro(l|ul) instead of simple_strto$1
  ...

21 files changed:
Documentation/hwmon/dme1737
Documentation/hwmon/lm63
Documentation/hwmon/ltc4245
Documentation/hwmon/sysfs-interface
Documentation/hwmon/tmp102 [new file with mode: 0644]
drivers/acpi/osl.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adm1031.c
drivers/hwmon/applesmc.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/dme1737.c
drivers/hwmon/emc1403.c [new file with mode: 0644]
drivers/hwmon/f71882fg.c
drivers/hwmon/lm63.c
drivers/hwmon/lm75.c
drivers/hwmon/lm90.c
drivers/hwmon/ltc4245.c
drivers/hwmon/tmp102.c [new file with mode: 0644]
drivers/hwmon/tmp401.c
include/linux/acpi.h

index 001d2e7..fc5df76 100644 (file)
@@ -9,11 +9,15 @@ Supported chips:
   * SMSC SCH3112, SCH3114, SCH3116
     Prefix: 'sch311x'
     Addresses scanned: none, address read from Super-I/O config space
-    Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
+    Datasheet: Available on the Internet
   * SMSC SCH5027
     Prefix: 'sch5027'
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
     Datasheet: Provided by SMSC upon request and under NDA
+  * SMSC SCH5127
+    Prefix: 'sch5127'
+    Addresses scanned: none, address read from Super-I/O config space
+    Datasheet: Provided by SMSC upon request and under NDA
 
 Authors:
     Juerg Haefliger <juergh@gmail.com>
@@ -36,8 +40,8 @@ Description
 -----------
 
 This driver implements support for the hardware monitoring capabilities of the
-SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
-SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
+SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, SCH311x,
+and SCH5127 Super-I/O chips. These chips feature monitoring of 3 temp sensors
 temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
 1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
 up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
@@ -48,14 +52,14 @@ Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
 the configuration of the chip. The driver will detect which features are
 present during initialization and create the sysfs attributes accordingly.
 
-For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
-pwm[5-6] don't exist.
+For the SCH311x and SCH5127, fan[1-3] and pwm[1-3] are always present and
+fan[4-6] and pwm[5-6] don't exist.
 
 The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
-accessible via SMBus, while the SCH311x only provides access via the ISA bus.
-The driver will therefore register itself as an I2C client driver if it detects
-a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
-chip.
+accessible via SMBus, while the SCH311x and SCH5127 only provide access via
+the ISA bus. The driver will therefore register itself as an I2C client driver
+if it detects a DME1737, A8000, or SCH5027 and as a platform driver if it
+detects a SCH311x or SCH5127 chip.
 
 
 Voltage Monitoring
@@ -76,7 +80,7 @@ DME1737, A8000:
        in6: Vbat       (+3.0V)                 0V - 4.38V
 
 SCH311x:
-       in0: +2.5V                              0V - 6.64V
+       in0: +2.5V                              0V - 3.32V
        in1: Vccp       (processor core)        0V - 2V
        in2: VCC        (internal +3.3V)        0V - 4.38V
        in3: +5V                                0V - 6.64V
@@ -93,6 +97,15 @@ SCH5027:
        in5: VTR        (+3.3V standby)         0V - 4.38V
        in6: Vbat       (+3.0V)                 0V - 4.38V
 
+SCH5127:
+       in0: +2.5                               0V - 3.32V
+       in1: Vccp       (processor core)        0V - 3V
+       in2: VCC        (internal +3.3V)        0V - 4.38V
+       in3: V2_IN                              0V - 1.5V
+       in4: V1_IN                              0V - 1.5V
+       in5: VTR        (+3.3V standby)         0V - 4.38V
+       in6: Vbat       (+3.0V)                 0V - 4.38V
+
 Each voltage input has associated min and max limits which trigger an alarm
 when crossed.
 
@@ -293,3 +306,21 @@ pwm[1-3]_auto_point1_pwm   RW      Auto PWM pwm point. Auto_point1 is the
 pwm[1-3]_auto_point2_pwm       RO      Auto PWM pwm point. Auto_point2 is the
                                        full-speed duty-cycle which is hard-
                                        wired to 255 (100% duty-cycle).
+
+Chip Differences
+----------------
+
+Feature                        dme1737 sch311x sch5027 sch5127
+-------------------------------------------------------
+temp[1-3]_offset       yes     yes
+vid                    yes
+zone3                  yes     yes     yes
+zone[1-3]_hyst         yes     yes
+pwm min/off            yes     yes
+fan3                   opt     yes     opt     yes
+pwm3                   opt     yes     opt     yes
+fan4                   opt             opt
+fan5                   opt             opt
+pwm5                   opt             opt
+fan6                   opt             opt
+pwm6                   opt             opt
index 31660bf..b9843ea 100644 (file)
@@ -7,6 +7,11 @@ Supported chips:
     Addresses scanned: I2C 0x4c
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/pf/LM/LM63.html
+  * National Semiconductor LM64
+    Prefix: 'lm64'
+    Addresses scanned: I2C 0x18 and 0x4e
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LM/LM64.html
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -55,3 +60,5 @@ The lm63 driver will not update its values more frequently than every
 second; reading them more often will do no harm, but will return 'old'
 values.
 
+The LM64 is effectively an LM63 with GPIO lines. The driver does not
+support these GPIO lines at present.
index 02838a4..86b5880 100644 (file)
@@ -72,9 +72,7 @@ in6_min_alarm         5v  output undervoltage alarm
 in7_min_alarm          3v  output undervoltage alarm
 in8_min_alarm          Vee (-12v) output undervoltage alarm
 
-in9_input              GPIO #1 voltage data
-in10_input             GPIO #2 voltage data
-in11_input             GPIO #3 voltage data
+in9_input              GPIO voltage data
 
 power1_input           12v power usage (mW)
 power2_input           5v  power usage (mW)
index 3de6b0b..d4e2917 100644 (file)
@@ -80,9 +80,9 @@ All entries (except name) are optional, and should only be created in a
 given driver if the chip has the feature.
 
 
-********
-* Name *
-********
+*********************
+* Global attributes *
+*********************
 
 name           The chip name.
                This should be a short, lowercase string, not containing
@@ -91,6 +91,13 @@ name         The chip name.
                I2C devices get this attribute created automatically.
                RO
 
+update_rate    The rate at which the chip will update readings.
+               Unit: millisecond
+               RW
+               Some devices have a variable update rate. This attribute
+               can be used to change the update rate to the desired
+               frequency.
+
 
 ************
 * Voltages *
diff --git a/Documentation/hwmon/tmp102 b/Documentation/hwmon/tmp102
new file mode 100644 (file)
index 0000000..8454a77
--- /dev/null
@@ -0,0 +1,26 @@
+Kernel driver tmp102
+====================
+
+Supported chips:
+  * Texas Instruments TMP102
+    Prefix: 'tmp102'
+    Addresses scanned: none
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp102.html
+
+Author:
+       Steven King <sfking@fdwdc.com>
+
+Description
+-----------
+
+The Texas Instruments TMP102 implements one temperature sensor.  Limits can be
+set through the Overtemperature Shutdown register and Hysteresis register.  The
+sensor is accurate to 0.5 degree over the range of -25 to +85 C, and to 1.0
+degree from -40 to +125 C. Resolution of the sensor is 0.0625 degree.  The
+operating temperature has a minimum of -55 C and a maximum of +150 C.
+
+The TMP102 has a programmable update rate that can select between 8, 4, 1, and
+0.5 Hz. (Currently the driver only supports the default of 4 Hz).
+
+The driver provides the common sysfs-interface for temperatures (see
+Documentation/hwmon/sysfs-interface under Temperatures).
index 4bc1c41..78418ce 100644 (file)
@@ -1207,6 +1207,15 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
 EXPORT_SYMBOL(acpi_check_mem_region);
 
 /*
+ * Let drivers know whether the resource checks are effective
+ */
+int acpi_resources_are_enforced(void)
+{
+       return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT;
+}
+EXPORT_SYMBOL(acpi_resources_are_enforced);
+
+/*
  * Acquire a spinlock.
  *
  * handle is a pointer to the spinlock_t.
index 6a9ac75..e19cf8e 100644 (file)
@@ -447,13 +447,14 @@ config SENSORS_IT87
          will be called it87.
 
 config SENSORS_LM63
-       tristate "National Semiconductor LM63"
+       tristate "National Semiconductor LM63 and LM64"
        depends on I2C
        help
-         If you say yes here you get support for the National Semiconductor
-         LM63 remote diode digital temperature sensor with integrated fan
-         control.  Such chips are found on the Tyan S4882 (Thunder K8QS Pro)
-         motherboard, among others.
+         If you say yes here you get support for the National
+         Semiconductor LM63 and LM64 remote diode digital temperature
+         sensors with integrated fan control.  Such chips are found
+         on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
+         others.
 
          This driver can also be built as a module.  If so, the module
          will be called lm63.
@@ -492,7 +493,8 @@ config SENSORS_LM75
                - NXP's LM75A
                - ST Microelectronics STDS75
                - TelCom (now Microchip) TCN75
-               - Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275
+               - Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
+                 TMP275
 
          This driver supports driver model based binding through board
          specific I2C device tables.
@@ -749,6 +751,16 @@ config SENSORS_DME1737
          This driver can also be built as a module.  If so, the module
          will be called dme1737.
 
+config SENSORS_EMC1403
+       tristate "SMSC EMC1403 thermal sensor"
+       depends on I2C
+       help
+         If you say yes here you get support for the SMSC EMC1403
+         temperature monitoring chip.
+
+         Threshold values can be configured using sysfs.
+         Data from the different diodes are accessible via sysfs.
+
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        help
@@ -831,6 +843,16 @@ config SENSORS_THMC50
          This driver can also be built as a module.  If so, the module
          will be called thmc50.
 
+config SENSORS_TMP102
+       tristate "Texas Instruments TMP102"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Texas Instruments TMP102
+         sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tmp102.
+
 config SENSORS_TMP401
        tristate "Texas Instruments TMP401 and compatibles"
        depends on I2C && EXPERIMENTAL
index 86920fb..2138ceb 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_ATXP1)   += atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
 obj-$(CONFIG_SENSORS_DME1737)  += dme1737.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
+obj-$(CONFIG_SENSORS_EMC1403)  += emc1403.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
 obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
 obj-$(CONFIG_SENSORS_F75375S)  += f75375s.o
@@ -90,6 +91,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1)        += smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
 obj-$(CONFIG_SENSORS_AMC6821)  += amc6821.o
 obj-$(CONFIG_SENSORS_THMC50)   += thmc50.o
+obj-$(CONFIG_SENSORS_TMP102)   += tmp102.o
 obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)   += tmp421.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
index 1644b92..15c1a96 100644 (file)
@@ -36,6 +36,7 @@
 #define ADM1031_REG_FAN_DIV(nr)                (0x20 + (nr))
 #define ADM1031_REG_PWM                        (0x22)
 #define ADM1031_REG_FAN_MIN(nr)                (0x10 + (nr))
+#define ADM1031_REG_FAN_FILTER         (0x23)
 
 #define ADM1031_REG_TEMP_OFFSET(nr)    (0x0d + (nr))
 #define ADM1031_REG_TEMP_MAX(nr)       (0x14 + 4 * (nr))
@@ -61,6 +62,9 @@
 #define ADM1031_CONF2_TACH2_ENABLE     0x08
 #define ADM1031_CONF2_TEMP_ENABLE(chan)        (0x10 << (chan))
 
+#define ADM1031_UPDATE_RATE_MASK       0x1c
+#define ADM1031_UPDATE_RATE_SHIFT      2
+
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
@@ -75,6 +79,7 @@ struct adm1031_data {
        int chip_type;
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
+       unsigned int update_rate;       /* In milliseconds */
        /* The chan_select_table contains the possible configurations for
         * auto fan control.
         */
@@ -738,6 +743,57 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
 static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
 
+/* Update Rate */
+static const unsigned int update_rates[] = {
+       16000, 8000, 4000, 2000, 1000, 500, 250, 125,
+};
+
+static ssize_t show_update_rate(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1031_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%u\n", data->update_rate);
+}
+
+static ssize_t set_update_rate(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1031_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int i, err;
+       u8 reg;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       /* find the nearest update rate from the table */
+       for (i = 0; i < ARRAY_SIZE(update_rates) - 1; i++) {
+               if (val >= update_rates[i])
+                       break;
+       }
+       /* if not found, we point to the last entry (lowest update rate) */
+
+       /* set the new update rate while preserving other settings */
+       reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+       reg &= ~ADM1031_UPDATE_RATE_MASK;
+       reg |= i << ADM1031_UPDATE_RATE_SHIFT;
+       adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
+
+       mutex_lock(&data->update_lock);
+       data->update_rate = update_rates[i];
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(update_rate, S_IRUGO | S_IWUSR, show_update_rate,
+                  set_update_rate);
+
 static struct attribute *adm1031_attributes[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
        &sensor_dev_attr_fan1_div.dev_attr.attr,
@@ -774,6 +830,7 @@ static struct attribute *adm1031_attributes[] = {
 
        &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
 
+       &dev_attr_update_rate.attr,
        &dev_attr_alarms.attr,
 
        NULL
@@ -900,6 +957,7 @@ static void adm1031_init_client(struct i2c_client *client)
 {
        unsigned int read_val;
        unsigned int mask;
+       int i;
        struct adm1031_data *data = i2c_get_clientdata(client);
 
        mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
@@ -919,18 +977,24 @@ static void adm1031_init_client(struct i2c_client *client)
                                ADM1031_CONF1_MONITOR_ENABLE);
        }
 
+       /* Read the chip's update rate */
+       mask = ADM1031_UPDATE_RATE_MASK;
+       read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
+       i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
+       data->update_rate = update_rates[i];
 }
 
 static struct adm1031_data *adm1031_update_device(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct adm1031_data *data = i2c_get_clientdata(client);
+       unsigned long next_update;
        int chan;
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
+       next_update = data->last_updated + msecs_to_jiffies(data->update_rate);
+       if (time_after(jiffies, next_update) || !data->valid) {
 
                dev_dbg(&client->dev, "Starting adm1031 update\n");
                for (chan = 0;
index f085c18..b6598aa 100644 (file)
@@ -148,6 +148,20 @@ static const char *temperature_sensors_sets[][41] = {
 /* Set 18: MacBook Pro 2,2 */
        { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
          "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
+/* Set 19: Macbook Pro 5,3 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
+         "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
+         "Tm0P", "Ts0P", "Ts0S", NULL },
+/* Set 20: MacBook Pro 5,4 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
+         "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
+/* Set 21: MacBook Pro 6,2 */
+       { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
+         "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
+         "Ts0P", "Ts0S", NULL },
+/* Set 22: MacBook Pro 7,1 */
+       { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
+         "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
 };
 
 /* List of keys used to read/write fan speeds */
@@ -646,6 +660,17 @@ out:
                return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
 }
 
+/* Displays sensor key as label */
+static ssize_t applesmc_show_sensor_label(struct device *dev,
+                       struct device_attribute *devattr, char *sysfsbuf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       const char *key =
+               temperature_sensors_sets[applesmc_temperature_set][attr->index];
+
+       return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+}
+
 /* Displays degree Celsius * 1000 */
 static ssize_t applesmc_show_temperature(struct device *dev,
                        struct device_attribute *devattr, char *sysfsbuf)
@@ -1113,6 +1138,86 @@ static const struct attribute_group fan_attribute_groups[] = {
 /*
  * Temperature sensors sysfs entries.
  */
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 24);
+static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 25);
+static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 26);
+static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 27);
+static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 28);
+static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 29);
+static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 30);
+static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 31);
+static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 32);
+static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 33);
+static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 34);
+static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 35);
+static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 36);
+static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 37);
+static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 38);
+static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
+                                       applesmc_show_sensor_label, NULL, 39);
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
@@ -1194,6 +1299,50 @@ static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
 static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 39);
 
+static struct attribute *label_attributes[] = {
+       &sensor_dev_attr_temp1_label.dev_attr.attr,
+       &sensor_dev_attr_temp2_label.dev_attr.attr,
+       &sensor_dev_attr_temp3_label.dev_attr.attr,
+       &sensor_dev_attr_temp4_label.dev_attr.attr,
+       &sensor_dev_attr_temp5_label.dev_attr.attr,
+       &sensor_dev_attr_temp6_label.dev_attr.attr,
+       &sensor_dev_attr_temp7_label.dev_attr.attr,
+       &sensor_dev_attr_temp8_label.dev_attr.attr,
+       &sensor_dev_attr_temp9_label.dev_attr.attr,
+       &sensor_dev_attr_temp10_label.dev_attr.attr,
+       &sensor_dev_attr_temp11_label.dev_attr.attr,
+       &sensor_dev_attr_temp12_label.dev_attr.attr,
+       &sensor_dev_attr_temp13_label.dev_attr.attr,
+       &sensor_dev_attr_temp14_label.dev_attr.attr,
+       &sensor_dev_attr_temp15_label.dev_attr.attr,
+       &sensor_dev_attr_temp16_label.dev_attr.attr,
+       &sensor_dev_attr_temp17_label.dev_attr.attr,
+       &sensor_dev_attr_temp18_label.dev_attr.attr,
+       &sensor_dev_attr_temp19_label.dev_attr.attr,
+       &sensor_dev_attr_temp20_label.dev_attr.attr,
+       &sensor_dev_attr_temp21_label.dev_attr.attr,
+       &sensor_dev_attr_temp22_label.dev_attr.attr,
+       &sensor_dev_attr_temp23_label.dev_attr.attr,
+       &sensor_dev_attr_temp24_label.dev_attr.attr,
+       &sensor_dev_attr_temp25_label.dev_attr.attr,
+       &sensor_dev_attr_temp26_label.dev_attr.attr,
+       &sensor_dev_attr_temp27_label.dev_attr.attr,
+       &sensor_dev_attr_temp28_label.dev_attr.attr,
+       &sensor_dev_attr_temp29_label.dev_attr.attr,
+       &sensor_dev_attr_temp30_label.dev_attr.attr,
+       &sensor_dev_attr_temp31_label.dev_attr.attr,
+       &sensor_dev_attr_temp32_label.dev_attr.attr,
+       &sensor_dev_attr_temp33_label.dev_attr.attr,
+       &sensor_dev_attr_temp34_label.dev_attr.attr,
+       &sensor_dev_attr_temp35_label.dev_attr.attr,
+       &sensor_dev_attr_temp36_label.dev_attr.attr,
+       &sensor_dev_attr_temp37_label.dev_attr.attr,
+       &sensor_dev_attr_temp38_label.dev_attr.attr,
+       &sensor_dev_attr_temp39_label.dev_attr.attr,
+       &sensor_dev_attr_temp40_label.dev_attr.attr,
+       NULL
+};
+
 static struct attribute *temperature_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -1241,6 +1390,10 @@ static struct attribute *temperature_attributes[] = {
 static const struct attribute_group temperature_attributes_group =
        { .attrs = temperature_attributes };
 
+static const struct attribute_group label_attributes_group = {
+       .attrs = label_attributes
+};
+
 /* Module stuff */
 
 /*
@@ -1363,6 +1516,14 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
        { .accelerometer = 0, .light = 0, .temperature_set = 17 },
 /* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
        { .accelerometer = 1, .light = 1, .temperature_set = 18 },
+/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 19 },
+/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 20 },
+/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 21 },
+/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 22 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1376,6 +1537,22 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
                &applesmc_dmi_data[7]},
+       { applesmc_dmi_match, "Apple MacBook Pro 7", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
+               &applesmc_dmi_data[22]},
+       { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
+               &applesmc_dmi_data[20]},
+       { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
+               &applesmc_dmi_data[19]},
+       { applesmc_dmi_match, "Apple MacBook Pro 6", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
+               &applesmc_dmi_data[21]},
        { applesmc_dmi_match, "Apple MacBook Pro 5", {
          DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
@@ -1518,7 +1695,8 @@ static int __init applesmc_init(void)
        for (i = 0;
             temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
             i++) {
-               if (temperature_attributes[i] == NULL) {
+               if (temperature_attributes[i] == NULL ||
+                   label_attributes[i] == NULL) {
                        printk(KERN_ERR "applesmc: More temperature sensors "
                                "in temperature_sensors_sets (at least %i)"
                                "than available sysfs files in "
@@ -1530,6 +1708,10 @@ static int __init applesmc_init(void)
                                                temperature_attributes[i]);
                if (ret)
                        goto out_temperature;
+               ret = sysfs_create_file(&pdev->dev.kobj,
+                                               label_attributes[i]);
+               if (ret)
+                       goto out_temperature;
        }
 
        if (applesmc_accelerometer) {
@@ -1580,6 +1762,7 @@ out_accelerometer:
        if (applesmc_accelerometer)
                applesmc_release_accelerometer();
 out_temperature:
+       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
        sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
 out_fans:
        while (fans_handled)
@@ -1609,6 +1792,7 @@ static void __exit applesmc_exit(void)
        }
        if (applesmc_accelerometer)
                applesmc_release_accelerometer();
+       sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
        sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
        while (fans_handled)
                sysfs_remove_group(&pdev->dev.kobj,
index 16c4202..653db1b 100644 (file)
@@ -1411,6 +1411,13 @@ static int __init atk0110_init(void)
 {
        int ret;
 
+       /* Make sure it's safe to access the device through ACPI */
+       if (!acpi_resources_are_enforced()) {
+               pr_err("atk: Resources not safely usable due to "
+                      "acpi_enforce_resources kernel parameter\n");
+               return -EBUSY;
+       }
+
        ret = acpi_bus_register_driver(&atk_driver);
        if (ret)
                pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
index 823dd28..980c17d 100644 (file)
@@ -1,12 +1,14 @@
 /*
- * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
- *             SCH5027 Super-I/O chips integrated hardware monitoring features.
- * Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x, SCH5027,
+ *             and SCH5127 Super-I/O chips integrated hardware monitoring
+ *             features.
+ * Copyright (c) 2007, 2008, 2009, 2010 Juerg Haefliger <juergh@gmail.com>
  *
  * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
  * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
- * if a SCH311x chip is found. Both types of chips have very similar hardware
- * monitoring capabilities but differ in the way they can be accessed.
+ * if a SCH311x or SCH5127 chip is found. Both types of chips have very
+ * similar hardware monitoring capabilities but differ in the way they can be
+ * accessed.
  *
  * 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
@@ -57,7 +59,7 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
 
-enum chips { dme1737, sch5027, sch311x };
+enum chips { dme1737, sch5027, sch311x, sch5127 };
 
 /* ---------------------------------------------------------------------
  * Registers
@@ -164,10 +166,29 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
 #define DME1737_VERSTEP_MASK   0xf8
 #define SCH311X_DEVICE         0x8c
 #define SCH5027_VERSTEP                0x69
+#define SCH5127_DEVICE         0x8e
+
+/* Device ID values (global configuration register index 0x20) */
+#define DME1737_ID_1   0x77
+#define DME1737_ID_2   0x78
+#define SCH3112_ID     0x7c
+#define SCH3114_ID     0x7d
+#define SCH3116_ID     0x7f
+#define SCH5027_ID     0x89
+#define SCH5127_ID     0x86
 
 /* Length of ISA address segment */
 #define DME1737_EXTENT 2
 
+/* chip-dependent features */
+#define HAS_TEMP_OFFSET                (1 << 0)                /* bit 0 */
+#define HAS_VID                        (1 << 1)                /* bit 1 */
+#define HAS_ZONE3              (1 << 2)                /* bit 2 */
+#define HAS_ZONE_HYST          (1 << 3)                /* bit 3 */
+#define HAS_PWM_MIN            (1 << 4)                /* bit 4 */
+#define HAS_FAN(ix)            (1 << ((ix) + 5))       /* bits 5-10 */
+#define HAS_PWM(ix)            (1 << ((ix) + 11))      /* bits 11-16 */
+
 /* ---------------------------------------------------------------------
  * Data structures and manipulation thereof
  * --------------------------------------------------------------------- */
@@ -187,8 +208,7 @@ struct dme1737_data {
 
        u8 vid;
        u8 pwm_rr_en;
-       u8 has_pwm;
-       u8 has_fan;
+       u32 has_features;
 
        /* Register values */
        u16 in[7];
@@ -224,8 +244,11 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
                                         3300};
 static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
                                         3300};
+static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300,
+                                        3300};
 #define IN_NOMINAL(type)       ((type) == sch311x ? IN_NOMINAL_SCH311x : \
                                 (type) == sch5027 ? IN_NOMINAL_SCH5027 : \
+                                (type) == sch5127 ? IN_NOMINAL_SCH5127 : \
                                 IN_NOMINAL_DME1737)
 
 /* Voltage input
@@ -568,7 +591,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
 
        /* Sample register contents every 1 sec */
        if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
-               if (data->type == dme1737) {
+               if (data->has_features & HAS_VID) {
                        data->vid = dme1737_read(data, DME1737_REG_VID) &
                                0x3f;
                }
@@ -599,7 +622,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                                        DME1737_REG_TEMP_MIN(ix));
                        data->temp_max[ix] = dme1737_read(data,
                                        DME1737_REG_TEMP_MAX(ix));
-                       if (data->type != sch5027) {
+                       if (data->has_features & HAS_TEMP_OFFSET) {
                                data->temp_offset[ix] = dme1737_read(data,
                                                DME1737_REG_TEMP_OFFSET(ix));
                        }
@@ -626,7 +649,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
                        /* Skip reading registers if optional fans are not
                         * present */
-                       if (!(data->has_fan & (1 << ix))) {
+                       if (!(data->has_features & HAS_FAN(ix))) {
                                continue;
                        }
                        data->fan[ix] = dme1737_read(data,
@@ -650,7 +673,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
                for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
                        /* Skip reading registers if optional PWMs are not
                         * present */
-                       if (!(data->has_pwm & (1 << ix))) {
+                       if (!(data->has_features & HAS_PWM(ix))) {
                                continue;
                        }
                        data->pwm[ix] = dme1737_read(data,
@@ -672,12 +695,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
 
                /* Thermal zone registers */
                for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
-                       data->zone_low[ix] = dme1737_read(data,
-                                       DME1737_REG_ZONE_LOW(ix));
-                       data->zone_abs[ix] = dme1737_read(data,
-                                       DME1737_REG_ZONE_ABS(ix));
+                       /* Skip reading registers if zone3 is not present */
+                       if ((ix == 2) && !(data->has_features & HAS_ZONE3)) {
+                               continue;
+                       }
+                       /* sch5127 zone2 registers are special */
+                       if ((ix == 1) && (data->type == sch5127)) {
+                               data->zone_low[1] = dme1737_read(data,
+                                               DME1737_REG_ZONE_LOW(2));
+                               data->zone_abs[1] = dme1737_read(data,
+                                               DME1737_REG_ZONE_ABS(2));
+                       } else {
+                               data->zone_low[ix] = dme1737_read(data,
+                                               DME1737_REG_ZONE_LOW(ix));
+                               data->zone_abs[ix] = dme1737_read(data,
+                                               DME1737_REG_ZONE_ABS(ix));
+                       }
                }
-               if (data->type != sch5027) {
+               if (data->has_features & HAS_ZONE_HYST) {
                        for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
                                data->zone_hyst[ix] = dme1737_read(data,
                                                DME1737_REG_ZONE_HYST(ix));
@@ -1594,10 +1629,6 @@ static struct attribute *dme1737_attr[] ={
        &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
        NULL
 };
 
@@ -1605,27 +1636,23 @@ static const struct attribute_group dme1737_group = {
        .attrs = dme1737_attr,
 };
 
-/* The following struct holds misc attributes, which are not available in all
- * chips. Their creation depends on the chip type which is determined during
- * module load. */
-static struct attribute *dme1737_misc_attr[] = {
-       /* Temperatures */
+/* The following struct holds temp offset attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737, SCH311x */
+static struct attribute *dme1737_temp_offset_attr[] = {
        &sensor_dev_attr_temp1_offset.dev_attr.attr,
        &sensor_dev_attr_temp2_offset.dev_attr.attr,
        &sensor_dev_attr_temp3_offset.dev_attr.attr,
-       /* Zones */
-       &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
-       &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
-       &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group dme1737_misc_group = {
-       .attrs = dme1737_misc_attr,
+static const struct attribute_group dme1737_temp_offset_group = {
+       .attrs = dme1737_temp_offset_attr,
 };
 
-/* The following struct holds VID-related attributes. Their creation
-   depends on the chip type which is determined during module load. */
+/* The following struct holds VID related attributes, which are not available
+ * in all chips. The following chips support them:
+ * DME1737 */
 static struct attribute *dme1737_vid_attr[] = {
        &dev_attr_vrm.attr,
        &dev_attr_cpu0_vid.attr,
@@ -1636,6 +1663,36 @@ static const struct attribute_group dme1737_vid_group = {
        .attrs = dme1737_vid_attr,
 };
 
+/* The following struct holds temp zone 3 related attributes, which are not
+ * available in all chips. The following chips support them:
+ * DME1737, SCH311x, SCH5027 */
+static struct attribute *dme1737_zone3_attr[] = {
+       &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone3_group = {
+       .attrs = dme1737_zone3_attr,
+};
+
+
+/* The following struct holds temp zone hysteresis  related attributes, which
+ * are not available in all chips. The following chips support them:
+ * DME1737, SCH311x */
+static struct attribute *dme1737_zone_hyst_attr[] = {
+       &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
+       &sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone_hyst_group = {
+       .attrs = dme1737_zone_hyst_attr,
+};
+
 /* The following structs hold the PWM attributes, some of which are optional.
  * Their creation depends on the chip configuration which is determined during
  * module load. */
@@ -1691,10 +1748,10 @@ static const struct attribute_group dme1737_pwm_group[] = {
        { .attrs = dme1737_pwm6_attr },
 };
 
-/* The following struct holds misc PWM attributes, which are not available in
- * all chips. Their creation depends on the chip type which is determined
+/* The following struct holds auto PWM min attributes, which are not available
+ * in all chips. Their creation depends on the chip type which is determined
  * during module load. */
-static struct attribute *dme1737_pwm_misc_attr[] = {
+static struct attribute *dme1737_auto_pwm_min_attr[] = {
        &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
        &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
        &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
@@ -1764,14 +1821,25 @@ static struct attribute *dme1737_zone_chmod_attr[] = {
        &sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group dme1737_zone_chmod_group = {
+       .attrs = dme1737_zone_chmod_attr,
+};
+
+
+/* The permissions of the following zone 3 attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_zone3_chmod_attr[] = {
        &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
        &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
        &sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
        NULL
 };
 
-static const struct attribute_group dme1737_zone_chmod_group = {
-       .attrs = dme1737_zone_chmod_attr,
+static const struct attribute_group dme1737_zone3_chmod_group = {
+       .attrs = dme1737_zone3_chmod_attr,
 };
 
 /* The permissions of the following PWM attributes are changed to read-
@@ -1887,30 +1955,35 @@ static void dme1737_remove_files(struct device *dev)
        int ix;
 
        for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
+               if (data->has_features & HAS_FAN(ix)) {
                        sysfs_remove_group(&dev->kobj,
                                           &dme1737_fan_group[ix]);
                }
        }
 
        for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
+               if (data->has_features & HAS_PWM(ix)) {
                        sysfs_remove_group(&dev->kobj,
                                           &dme1737_pwm_group[ix]);
-                       if (data->type != sch5027 && ix < 3) {
+                       if ((data->has_features & HAS_PWM_MIN) && ix < 3) {
                                sysfs_remove_file(&dev->kobj,
-                                                 dme1737_pwm_misc_attr[ix]);
+                                               dme1737_auto_pwm_min_attr[ix]);
                        }
                }
        }
 
-       if (data->type != sch5027) {
-               sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
+       if (data->has_features & HAS_TEMP_OFFSET) {
+               sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group);
        }
-       if (data->type == dme1737) {
+       if (data->has_features & HAS_VID) {
                sysfs_remove_group(&dev->kobj, &dme1737_vid_group);
        }
-
+       if (data->has_features & HAS_ZONE3) {
+               sysfs_remove_group(&dev->kobj, &dme1737_zone3_group);
+       }
+       if (data->has_features & HAS_ZONE_HYST) {
+               sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group);
+       }
        sysfs_remove_group(&dev->kobj, &dme1737_group);
 
        if (!data->client) {
@@ -1934,23 +2007,31 @@ static int dme1737_create_files(struct device *dev)
                goto exit_remove;
        }
 
-       /* Create misc sysfs attributes */
-       if ((data->type != sch5027) &&
+       /* Create chip-dependent sysfs attributes */
+       if ((data->has_features & HAS_TEMP_OFFSET) &&
            (err = sysfs_create_group(&dev->kobj,
-                                     &dme1737_misc_group))) {
+                                     &dme1737_temp_offset_group))) {
                goto exit_remove;
        }
-
-       /* Create VID-related sysfs attributes */
-       if ((data->type == dme1737) &&
+       if ((data->has_features & HAS_VID) &&
            (err = sysfs_create_group(&dev->kobj,
                                      &dme1737_vid_group))) {
                goto exit_remove;
        }
+       if ((data->has_features & HAS_ZONE3) &&
+           (err = sysfs_create_group(&dev->kobj,
+                                     &dme1737_zone3_group))) {
+               goto exit_remove;
+       }
+       if ((data->has_features & HAS_ZONE_HYST) &&
+           (err = sysfs_create_group(&dev->kobj,
+                                     &dme1737_zone_hyst_group))) {
+               goto exit_remove;
+       }
 
        /* Create fan sysfs attributes */
        for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
-               if (data->has_fan & (1 << ix)) {
+               if (data->has_features & HAS_FAN(ix)) {
                        if ((err = sysfs_create_group(&dev->kobj,
                                                &dme1737_fan_group[ix]))) {
                                goto exit_remove;
@@ -1960,14 +2041,14 @@ static int dme1737_create_files(struct device *dev)
 
        /* Create PWM sysfs attributes */
        for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
-               if (data->has_pwm & (1 << ix)) {
+               if (data->has_features & HAS_PWM(ix)) {
                        if ((err = sysfs_create_group(&dev->kobj,
                                                &dme1737_pwm_group[ix]))) {
                                goto exit_remove;
                        }
-                       if (data->type != sch5027 && ix < 3 &&
+                       if ((data->has_features & HAS_PWM_MIN) && ix < 3 &&
                            (err = sysfs_create_file(&dev->kobj,
-                                               dme1737_pwm_misc_attr[ix]))) {
+                                       dme1737_auto_pwm_min_attr[ix]))) {
                                goto exit_remove;
                        }
                }
@@ -1983,21 +2064,30 @@ static int dme1737_create_files(struct device *dev)
                dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
                                    S_IRUGO | S_IWUSR);
 
-               /* Change permissions of misc sysfs attributes */
-               if (data->type != sch5027) {
-                       dme1737_chmod_group(dev, &dme1737_misc_group,
+               /* Change permissions of chip-dependent sysfs attributes */
+               if (data->has_features & HAS_TEMP_OFFSET) {
+                       dme1737_chmod_group(dev, &dme1737_temp_offset_group,
+                                           S_IRUGO | S_IWUSR);
+               }
+               if (data->has_features & HAS_ZONE3) {
+                       dme1737_chmod_group(dev, &dme1737_zone3_chmod_group,
+                                           S_IRUGO | S_IWUSR);
+               }
+               if (data->has_features & HAS_ZONE_HYST) {
+                       dme1737_chmod_group(dev, &dme1737_zone_hyst_group,
                                            S_IRUGO | S_IWUSR);
                }
 
                /* Change permissions of PWM sysfs attributes */
                for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
-                       if (data->has_pwm & (1 << ix)) {
+                       if (data->has_features & HAS_PWM(ix)) {
                                dme1737_chmod_group(dev,
                                                &dme1737_pwm_chmod_group[ix],
                                                S_IRUGO | S_IWUSR);
-                               if (data->type != sch5027 && ix < 3) {
+                               if ((data->has_features & HAS_PWM_MIN) &&
+                                   ix < 3) {
                                        dme1737_chmod_file(dev,
-                                               dme1737_pwm_misc_attr[ix],
+                                               dme1737_auto_pwm_min_attr[ix],
                                                S_IRUGO | S_IWUSR);
                                }
                        }
@@ -2005,7 +2095,7 @@ static int dme1737_create_files(struct device *dev)
 
                /* Change permissions of pwm[1-3] if in manual mode */
                for (ix = 0; ix < 3; ix++) {
-                       if ((data->has_pwm & (1 << ix)) &&
+                       if ((data->has_features & HAS_PWM(ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
                                dme1737_chmod_file(dev,
                                                dme1737_pwm_chmod_attr[ix],
@@ -2052,20 +2142,20 @@ static int dme1737_init_device(struct device *dev)
                return -EFAULT;
        }
 
-       /* Determine which optional fan and pwm features are enabled/present */
+       /* Determine which optional fan and pwm features are enabled (only
+        * valid for I2C devices) */
        if (client) {   /* I2C chip */
                data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
                /* Check if optional fan3 input is enabled */
                if (data->config2 & 0x04) {
-                       data->has_fan |= (1 << 2);
+                       data->has_features |= HAS_FAN(2);
                }
 
                /* Fan4 and pwm3 are only available if the client's I2C address
                 * is the default 0x2e. Otherwise the I/Os associated with
                 * these functions are used for addr enable/select. */
                if (client->addr == 0x2e) {
-                       data->has_fan |= (1 << 3);
-                       data->has_pwm |= (1 << 2);
+                       data->has_features |= HAS_FAN(3) | HAS_PWM(2);
                }
 
                /* Determine which of the optional fan[5-6] and pwm[5-6]
@@ -2077,26 +2167,40 @@ static int dme1737_init_device(struct device *dev)
                        dev_warn(dev, "Failed to query Super-IO for optional "
                                 "features.\n");
                }
-       } else {   /* ISA chip */
-               /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
-                * don't exist in the ISA chip. */
-               data->has_fan |= (1 << 2);
-               data->has_pwm |= (1 << 2);
        }
 
-       /* Fan1, fan2, pwm1, and pwm2 are always present */
-       data->has_fan |= 0x03;
-       data->has_pwm |= 0x03;
+       /* Fan[1-2] and pwm[1-2] are present in all chips */
+       data->has_features |= HAS_FAN(0) | HAS_FAN(1) | HAS_PWM(0) | HAS_PWM(1);
+
+       /* Chip-dependent features */
+       switch (data->type) {
+       case dme1737:
+               data->has_features |= HAS_TEMP_OFFSET | HAS_VID | HAS_ZONE3 |
+                       HAS_ZONE_HYST | HAS_PWM_MIN;
+               break;
+       case sch311x:
+               data->has_features |= HAS_TEMP_OFFSET | HAS_ZONE3 |
+                       HAS_ZONE_HYST | HAS_PWM_MIN | HAS_FAN(2) | HAS_PWM(2);
+               break;
+       case sch5027:
+               data->has_features |= HAS_ZONE3;
+               break;
+       case sch5127:
+               data->has_features |= HAS_FAN(2) | HAS_PWM(2);
+               break;
+       default:
+               break;
+       }
 
        dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
                 "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
-                (data->has_pwm & (1 << 2)) ? "yes" : "no",
-                (data->has_pwm & (1 << 4)) ? "yes" : "no",
-                (data->has_pwm & (1 << 5)) ? "yes" : "no",
-                (data->has_fan & (1 << 2)) ? "yes" : "no",
-                (data->has_fan & (1 << 3)) ? "yes" : "no",
-                (data->has_fan & (1 << 4)) ? "yes" : "no",
-                (data->has_fan & (1 << 5)) ? "yes" : "no");
+                (data->has_features & HAS_PWM(2)) ? "yes" : "no",
+                (data->has_features & HAS_PWM(4)) ? "yes" : "no",
+                (data->has_features & HAS_PWM(5)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(2)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(3)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(4)) ? "yes" : "no",
+                (data->has_features & HAS_FAN(5)) ? "yes" : "no");
 
        reg = dme1737_read(data, DME1737_REG_TACH_PWM);
        /* Inform if fan-to-pwm mapping differs from the default */
@@ -2122,7 +2226,7 @@ static int dme1737_init_device(struct device *dev)
                for (ix = 0; ix < 3; ix++) {
                        data->pwm_config[ix] = dme1737_read(data,
                                                DME1737_REG_PWM_CONFIG(ix));
-                       if ((data->has_pwm & (1 << ix)) &&
+                       if ((data->has_features & HAS_PWM(ix)) &&
                            (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
                                dev_info(dev, "Switching pwm%d to "
                                         "manual mode.\n", ix + 1);
@@ -2142,7 +2246,7 @@ static int dme1737_init_device(struct device *dev)
        data->pwm_acz[2] = 4;   /* pwm3 -> zone3 */
 
        /* Set VRM */
-       if (data->type == dme1737) {
+       if (data->has_features & HAS_VID) {
                data->vrm = vid_which_vrm();
        }
 
@@ -2163,10 +2267,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
        dme1737_sio_enter(sio_cip);
 
        /* Check device ID
-        * The DME1737 can return either 0x78 or 0x77 as its device ID.
-        * The SCH5027 returns 0x89 as its device ID. */
+        * We currently know about two kinds of DME1737 and SCH5027. */
        reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
-       if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
+       if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 ||
+             reg == SCH5027_ID)) {
                err = -ENODEV;
                goto exit;
        }
@@ -2185,16 +2289,16 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
         * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
         * to '10' if the respective feature is enabled. */
        if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
-               data->has_fan |= (1 << 5);
+               data->has_features |= HAS_FAN(5);
        }
        if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
-               data->has_pwm |= (1 << 5);
+               data->has_features |= HAS_PWM(5);
        }
        if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
-               data->has_fan |= (1 << 4);
+               data->has_features |= HAS_FAN(4);
        }
        if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
-               data->has_pwm |= (1 << 4);
+               data->has_features |= HAS_PWM(4);
        }
 
 exit:
@@ -2222,7 +2326,6 @@ static int dme1737_i2c_detect(struct i2c_client *client,
        if (company == DME1737_COMPANY_SMSC &&
            verstep == SCH5027_VERSTEP) {
                name = "sch5027";
-
        } else if (company == DME1737_COMPANY_SMSC &&
                   (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
                name = "dme1737";
@@ -2329,10 +2432,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
        dme1737_sio_enter(sio_cip);
 
        /* Check device ID
-        * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
-        * SCH3116 (0x7f). */
+        * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 */
        reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
-       if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+       if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID ||
+             reg == SCH5127_ID)) {
                err = -ENODEV;
                goto exit;
        }
@@ -2424,23 +2527,42 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
 
        /* Skip chip detection if module is loaded with force_id parameter */
-       if (!force_id) {
+       switch (force_id) {
+       case SCH3112_ID:
+       case SCH3114_ID:
+       case SCH3116_ID:
+               data->type = sch311x;
+               break;
+       case SCH5127_ID:
+               data->type = sch5127;
+               break;
+       default:
                company = dme1737_read(data, DME1737_REG_COMPANY);
                device = dme1737_read(data, DME1737_REG_DEVICE);
 
-               if (!((company == DME1737_COMPANY_SMSC) &&
-                     (device == SCH311X_DEVICE))) {
+               if ((company == DME1737_COMPANY_SMSC) &&
+                   (device == SCH311X_DEVICE)) {
+                       data->type = sch311x;
+               } else if ((company == DME1737_COMPANY_SMSC) &&
+                          (device == SCH5127_DEVICE)) {
+                       data->type = sch5127;
+               } else {
                        err = -ENODEV;
                        goto exit_kfree;
                }
        }
-       data->type = sch311x;
 
-       /* Fill in the remaining client fields and initialize the mutex */
-       data->name = "sch311x";
+       if (data->type == sch5127) {
+               data->name = "sch5127";
+       } else {
+               data->name = "sch311x";
+       }
+
+       /* Initialize the mutex */
        mutex_init(&data->update_lock);
 
-       dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
+       dev_info(dev, "Found a %s chip at 0x%04x\n",
+                data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr);
 
        /* Initialize the chip */
        if ((err = dme1737_init_device(dev))) {
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
new file mode 100644 (file)
index 0000000..0e4b564
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * emc1403.c - SMSC Thermal Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO
+ *     -       cache alarm and critical limit registers
+ *     -       add emc1404 support
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/mutex.h>
+
+#define THERMAL_PID_REG                0xfd
+#define THERMAL_SMSC_ID_REG    0xfe
+#define THERMAL_REVISION_REG   0xff
+
+struct thermal_data {
+       struct device *hwmon_dev;
+       struct mutex mutex;
+       /* Cache the hyst value so we don't keep re-reading it. In theory
+          we could cache it forever as nobody else should be writing it. */
+       u8 cached_hyst;
+       unsigned long hyst_valid;
+};
+
+static ssize_t show_temp(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       int retval = i2c_smbus_read_byte_data(client, sda->index);
+
+       if (retval < 0)
+               return retval;
+       return sprintf(buf, "%d000\n", retval);
+}
+
+static ssize_t show_bit(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
+       int retval = i2c_smbus_read_byte_data(client, sda->nr);
+
+       if (retval < 0)
+               return retval;
+       retval &= sda->index;
+       return sprintf(buf, "%d\n", retval ? 1 : 0);
+}
+
+static ssize_t store_temp(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       unsigned long val;
+       int retval;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+       retval = i2c_smbus_write_byte_data(client, sda->index,
+                                       DIV_ROUND_CLOSEST(val, 1000));
+       if (retval < 0)
+               return retval;
+       return count;
+}
+
+static ssize_t show_hyst(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct thermal_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       int retval;
+       int hyst;
+
+       retval = i2c_smbus_read_byte_data(client, sda->index);
+       if (retval < 0)
+               return retval;
+
+       if (time_after(jiffies, data->hyst_valid)) {
+               hyst = i2c_smbus_read_byte_data(client, 0x21);
+               if (hyst < 0)
+                       return retval;
+               data->cached_hyst = hyst;
+               data->hyst_valid = jiffies + HZ;
+       }
+       return sprintf(buf, "%d000\n", retval - data->cached_hyst);
+}
+
+static ssize_t store_hyst(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct thermal_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       int retval;
+       int hyst;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       mutex_lock(&data->mutex);
+       retval = i2c_smbus_read_byte_data(client, sda->index);
+       if (retval < 0)
+               goto fail;
+
+       hyst = val - retval * 1000;
+       hyst = DIV_ROUND_CLOSEST(hyst, 1000);
+       if (hyst < 0 || hyst > 255) {
+               retval = -ERANGE;
+               goto fail;
+       }
+
+       retval = i2c_smbus_write_byte_data(client, 0x21, hyst);
+       if (retval == 0) {
+               retval = count;
+               data->cached_hyst = hyst;
+               data->hyst_valid = jiffies + HZ;
+       }
+fail:
+       mutex_unlock(&data->mutex);
+       return retval;
+}
+
+/*
+ *     Sensors. We pass the actual i2c register to the methods.
+ */
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x06);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x05);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x20);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0x00);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x01);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x20);
+
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x08);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x07);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x19);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x02);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x02);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x19);
+
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x16);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x15);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR,
+       show_temp, store_temp, 0x1A);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO,
+       show_bit, NULL, 0x36, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO,
+       show_bit, NULL, 0x35, 0x04);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO,
+       show_bit, NULL, 0x37, 0x04);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR,
+       show_hyst, store_hyst, 0x1A);
+
+static struct attribute *mid_att_thermal[] = {
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group m_thermal_gr = {
+       .attrs = mid_att_thermal
+};
+
+static int emc1403_detect(struct i2c_client *client,
+                       struct i2c_board_info *info)
+{
+       int id;
+       /* Check if thermal chip is SMSC and EMC1403 */
+
+       id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG);
+       if (id != 0x5d)
+               return -ENODEV;
+
+       /* Note: 0x25 is the 1404 which is very similar and this
+          driver could be extended */
+       id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG);
+       if (id != 0x21)
+               return -ENODEV;
+
+       id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG);
+       if (id != 0x01)
+               return -ENODEV;
+
+       strlcpy(info->type, "emc1403", I2C_NAME_SIZE);
+       return 0;
+}
+
+static int emc1403_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int res;
+       struct thermal_data *data;
+
+       data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
+       if (data == NULL) {
+               dev_warn(&client->dev, "out of memory");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->mutex);
+       data->hyst_valid = jiffies - 1;         /* Expired */
+
+       res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
+       if (res) {
+               dev_warn(&client->dev, "create group failed\n");
+               hwmon_device_unregister(data->hwmon_dev);
+               goto thermal_error1;
+       }
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               res = PTR_ERR(data->hwmon_dev);
+               dev_warn(&client->dev, "register hwmon dev failed\n");
+               goto thermal_error2;
+       }
+       dev_info(&client->dev, "EMC1403 Thermal chip found\n");
+       return res;
+
+thermal_error2:
+       sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
+thermal_error1:
+       kfree(data);
+       return res;
+}
+
+static int emc1403_remove(struct i2c_client *client)
+{
+       struct thermal_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
+       kfree(data);
+       return 0;
+}
+
+static const unsigned short emc1403_address_list[] = {
+       0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id emc1403_idtable[] = {
+       { "emc1403", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
+
+static struct i2c_driver sensor_emc1403 = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+               .name = "emc1403",
+       },
+       .detect = emc1403_detect,
+       .probe = emc1403_probe,
+       .remove = emc1403_remove,
+       .id_table = emc1403_idtable,
+       .address_list = emc1403_address_list,
+};
+
+static int __init sensor_emc1403_init(void)
+{
+       return i2c_add_driver(&sensor_emc1403);
+}
+
+static void  __exit sensor_emc1403_exit(void)
+{
+       i2c_del_driver(&sensor_emc1403);
+}
+
+module_init(sensor_emc1403_init);
+module_exit(sensor_emc1403_exit);
+
+MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
+MODULE_DESCRIPTION("emc1403 Thermal Driver");
+MODULE_LICENSE("GPL v2");
index a95fa42..537841e 100644 (file)
@@ -856,21 +856,19 @@ static inline int superio_inb(int base, int reg)
 static int superio_inw(int base, int reg)
 {
        int val;
-       outb(reg++, base);
-       val = inb(base + 1) << 8;
-       outb(reg, base);
-       val |= inb(base + 1);
+       val  = superio_inb(base, reg) << 8;
+       val |= superio_inb(base, reg + 1);
        return val;
 }
 
 static inline void superio_enter(int base)
 {
        /* according to the datasheet the key must be send twice! */
-       outb( SIO_UNLOCK_KEY, base);
-       outb( SIO_UNLOCK_KEY, base);
+       outb(SIO_UNLOCK_KEY, base);
+       outb(SIO_UNLOCK_KEY, base);
 }
 
-static inline void superio_select( int base, int ld)
+static inline void superio_select(int base, int ld)
 {
        outb(SIO_REG_LDSEL, base);
        outb(ld, base + 1);
@@ -905,10 +903,8 @@ static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
 {
        u16 val;
 
-       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);
+       val  = f71882fg_read8(data, reg) << 8;
+       val |= f71882fg_read8(data, reg + 1);
 
        return val;
 }
@@ -921,10 +917,8 @@ static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
 
 static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
 {
-       outb(reg++, data->addr + ADDR_REG_OFFSET);
-       outb(val >> 8, data->addr + DATA_REG_OFFSET);
-       outb(reg, data->addr + ADDR_REG_OFFSET);
-       outb(val & 255, data->addr + DATA_REG_OFFSET);
+       f71882fg_write8(data, reg,     val >> 8);
+       f71882fg_write8(data, reg + 1, val & 0xff);
 }
 
 static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
@@ -945,7 +939,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
        mutex_lock(&data->update_lock);
 
        /* Update once every 60 seconds */
-       if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
+       if (time_after(jiffies, data->last_limits + 60 * HZ) ||
                        !data->valid) {
                if (data->type == f71882fg || data->type == f71889fg) {
                        data->in1_max =
@@ -1127,8 +1121,12 @@ static ssize_t store_fan_full_speed(struct device *dev,
                                    const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        val = SENSORS_LIMIT(val, 23, 1500000);
        val = fan_to_reg(val);
@@ -1157,8 +1155,12 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
@@ -1206,7 +1208,14 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       long val = simple_strtol(buf, NULL, 10) / 8;
+       int err;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 8;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1233,8 +1242,12 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
@@ -1299,8 +1312,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1333,10 +1352,16 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
        ssize_t ret = count;
        u8 reg;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        mutex_lock(&data->update_lock);
 
@@ -1372,8 +1397,14 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1427,8 +1458,12 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute
        *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
@@ -1490,8 +1525,13 @@ static ssize_t store_pwm(struct device *dev,
                         size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1551,8 +1591,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
                                *devattr, const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        /* Special case for F8000 pwm channel 3 which only does auto mode */
        if (data->type == f8000 && nr == 2 && val != 2)
@@ -1626,9 +1670,14 @@ static ssize_t store_pwm_auto_point_pwm(struct device *dev,
                                        const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int pwm = to_sensor_dev_attr_2(devattr)->index;
+       int err, pwm = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
        val = SENSORS_LIMIT(val, 0, 255);
 
        mutex_lock(&data->update_lock);
@@ -1674,10 +1723,16 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
                                              const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
        u8 reg;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_temp[nr][point] =
@@ -1716,8 +1771,12 @@ static ssize_t store_pwm_interpolate(struct device *dev,
                                     const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_mapping[nr] =
@@ -1752,8 +1811,12 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
                                            const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int nr = to_sensor_dev_attr_2(devattr)->index;
-       long val = simple_strtol(buf, NULL, 10);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
 
        switch (val) {
        case 1:
@@ -1798,9 +1861,15 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
                                         const char *buf, size_t count)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
-       int pwm = to_sensor_dev_attr_2(devattr)->index;
+       int err, pwm = to_sensor_dev_attr_2(devattr)->index;
        int point = to_sensor_dev_attr_2(devattr)->nr;
-       long val = simple_strtol(buf, NULL, 10) / 1000;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val /= 1000;
 
        if (data->type == f71889fg)
                val = SENSORS_LIMIT(val, -128, 127);
@@ -2109,6 +2178,13 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        int err = -ENODEV;
        u16 devid;
 
+       /* Don't step on other drivers' I/O space by accident */
+       if (!request_region(sioaddr, 2, DRVNAME)) {
+               printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
+                               (int)sioaddr);
+               return -EBUSY;
+       }
+
        superio_enter(sioaddr);
 
        devid = superio_inw(sioaddr, SIO_REG_MANID);
@@ -2151,8 +2227,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        }
 
        *address = superio_inw(sioaddr, SIO_REG_ADDR);
-       if (*address == 0)
-       {
+       if (*address == 0) {
                printk(KERN_WARNING DRVNAME ": Base address not set\n");
                goto exit;
        }
@@ -2164,6 +2239,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
        superio_exit(sioaddr);
+       release_region(sioaddr, 2);
        return err;
 }
 
index bf81aff..776aeb3 100644 (file)
@@ -53,7 +53,7 @@
  * Address is fully defined internally and cannot be changed.
  */
 
-static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 
 /*
  * The LM63 registers
@@ -131,12 +131,15 @@ static struct lm63_data *lm63_update_device(struct device *dev);
 static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
 static void lm63_init_client(struct i2c_client *client);
 
+enum chips { lm63, lm64 };
+
 /*
  * Driver data (common to all clients)
  */
 
 static const struct i2c_device_id lm63_id[] = {
-       { "lm63", 0 },
+       { "lm63", lm63 },
+       { "lm64", lm64 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -422,6 +425,7 @@ static int lm63_detect(struct i2c_client *new_client,
        struct i2c_adapter *adapter = new_client->adapter;
        u8 man_id, chip_id, reg_config1, reg_config2;
        u8 reg_alert_status, reg_alert_mask;
+       int address = new_client->addr;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -439,7 +443,6 @@ static int lm63_detect(struct i2c_client *new_client,
                         LM63_REG_ALERT_MASK);
 
        if (man_id != 0x01 /* National Semiconductor */
-        || chip_id != 0x41 /* LM63 */
         || (reg_config1 & 0x18) != 0x00
         || (reg_config2 & 0xF8) != 0x00
         || (reg_alert_status & 0x20) != 0x00
@@ -450,7 +453,12 @@ static int lm63_detect(struct i2c_client *new_client,
                return -ENODEV;
        }
 
-       strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+       if (chip_id == 0x41 && address == 0x4c)
+               strlcpy(info->type, "lm63", I2C_NAME_SIZE);
+       else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
+               strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+       else
+               return -ENODEV;
 
        return 0;
 }
index 8ae2cfe..5646342 100644 (file)
@@ -46,6 +46,7 @@ enum lm75_type {              /* keep sorted in alphabetical order */
        tcn75,
        tmp100,
        tmp101,
+       tmp105,
        tmp175,
        tmp275,
        tmp75,
@@ -220,6 +221,7 @@ static const struct i2c_device_id lm75_ids[] = {
        { "tcn75", tcn75, },
        { "tmp100", tmp100, },
        { "tmp101", tmp101, },
+       { "tmp105", tmp105, },
        { "tmp175", tmp175, },
        { "tmp275", tmp275, },
        { "tmp75", tmp75, },
index 7cc2708..760ef72 100644 (file)
@@ -982,7 +982,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+       if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
+        || !data->valid) {
                u8 h, l;
 
                dev_dbg(&client->dev, "Updating lm90 data.\n");
index 65c232a..21d201b 100644 (file)
@@ -45,9 +45,7 @@ enum ltc4245_cmd {
        LTC4245_VEEIN                   = 0x19,
        LTC4245_VEESENSE                = 0x1a,
        LTC4245_VEEOUT                  = 0x1b,
-       LTC4245_GPIOADC1                = 0x1c,
-       LTC4245_GPIOADC2                = 0x1d,
-       LTC4245_GPIOADC3                = 0x1e,
+       LTC4245_GPIOADC                 = 0x1c,
 };
 
 struct ltc4245_data {
@@ -61,7 +59,7 @@ struct ltc4245_data {
        u8 cregs[0x08];
 
        /* Voltage registers */
-       u8 vregs[0x0f];
+       u8 vregs[0x0d];
 };
 
 static struct ltc4245_data *ltc4245_update_device(struct device *dev)
@@ -86,7 +84,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
                                data->cregs[i] = val;
                }
 
-               /* Read voltage registers -- 0x10 to 0x1f */
+               /* Read voltage registers -- 0x10 to 0x1c */
                for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
                        val = i2c_smbus_read_byte_data(client, i+0x10);
                        if (unlikely(val < 0))
@@ -128,9 +126,7 @@ static int ltc4245_get_voltage(struct device *dev, u8 reg)
        case LTC4245_VEEOUT:
                voltage = regval * -55;
                break;
-       case LTC4245_GPIOADC1:
-       case LTC4245_GPIOADC2:
-       case LTC4245_GPIOADC3:
+       case LTC4245_GPIOADC:
                voltage = regval * 10;
                break;
        default:
@@ -297,9 +293,7 @@ LTC4245_ALARM(in7_min_alarm,        (1 << 2),       LTC4245_FAULT2);
 LTC4245_ALARM(in8_min_alarm,   (1 << 3),       LTC4245_FAULT2);
 
 /* GPIO voltages */
-LTC4245_VOLTAGE(in9_input,                     LTC4245_GPIOADC1);
-LTC4245_VOLTAGE(in10_input,                    LTC4245_GPIOADC2);
-LTC4245_VOLTAGE(in11_input,                    LTC4245_GPIOADC3);
+LTC4245_VOLTAGE(in9_input,                     LTC4245_GPIOADC);
 
 /* Power Consumption (virtual) */
 LTC4245_POWER(power1_input,                    LTC4245_12VSENSE);
@@ -342,8 +336,6 @@ static struct attribute *ltc4245_attributes[] = {
        &sensor_dev_attr_in8_min_alarm.dev_attr.attr,
 
        &sensor_dev_attr_in9_input.dev_attr.attr,
-       &sensor_dev_attr_in10_input.dev_attr.attr,
-       &sensor_dev_attr_in11_input.dev_attr.attr,
 
        &sensor_dev_attr_power1_input.dev_attr.attr,
        &sensor_dev_attr_power2_input.dev_attr.attr,
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
new file mode 100644 (file)
index 0000000..8013895
--- /dev/null
@@ -0,0 +1,321 @@
+/* Texas Instruments TMP102 SMBus temperature sensor driver
+ *
+ * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+#define        DRIVER_NAME "tmp102"
+
+#define        TMP102_TEMP_REG                 0x00
+#define        TMP102_CONF_REG                 0x01
+/* note: these bit definitions are byte swapped */
+#define                TMP102_CONF_SD          0x0100
+#define                TMP102_CONF_TM          0x0200
+#define                TMP102_CONF_POL         0x0400
+#define                TMP102_CONF_F0          0x0800
+#define                TMP102_CONF_F1          0x1000
+#define                TMP102_CONF_R0          0x2000
+#define                TMP102_CONF_R1          0x4000
+#define                TMP102_CONF_OS          0x8000
+#define                TMP102_CONF_EM          0x0010
+#define                TMP102_CONF_AL          0x0020
+#define                TMP102_CONF_CR0         0x0040
+#define                TMP102_CONF_CR1         0x0080
+#define        TMP102_TLOW_REG                 0x02
+#define        TMP102_THIGH_REG                0x03
+
+struct tmp102 {
+       struct device *hwmon_dev;
+       struct mutex lock;
+       u16 config_orig;
+       unsigned long last_update;
+       int temp[3];
+};
+
+/* SMBus specifies low byte first, but the TMP102 returns high byte first,
+ * so we have to swab16 the values */
+static inline int tmp102_read_reg(struct i2c_client *client, u8 reg)
+{
+       int result = i2c_smbus_read_word_data(client, reg);
+       return result < 0 ? result : swab16(result);
+}
+
+static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
+{
+       return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
+static inline int tmp102_reg_to_mC(s16 val)
+{
+       return ((val & ~0x01) * 1000) / 128;
+}
+
+/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
+static inline u16 tmp102_mC_to_reg(int val)
+{
+       return (val * 128) / 1000;
+}
+
+static const u8 tmp102_reg[] = {
+       TMP102_TEMP_REG,
+       TMP102_TLOW_REG,
+       TMP102_THIGH_REG,
+};
+
+static struct tmp102 *tmp102_update_device(struct i2c_client *client)
+{
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+
+       mutex_lock(&tmp102->lock);
+       if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
+                       int status = tmp102_read_reg(client, tmp102_reg[i]);
+                       if (status > -1)
+                               tmp102->temp[i] = tmp102_reg_to_mC(status);
+               }
+               tmp102->last_update = jiffies;
+       }
+       mutex_unlock(&tmp102->lock);
+       return tmp102;
+}
+
+static ssize_t tmp102_show_temp(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
+
+       return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
+}
+
+static ssize_t tmp102_set_temp(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+       long val;
+       int status;
+
+       if (strict_strtol(buf, 10, &val) < 0)
+               return -EINVAL;
+       val = SENSORS_LIMIT(val, -256000, 255000);
+
+       mutex_lock(&tmp102->lock);
+       tmp102->temp[sda->index] = val;
+       status = tmp102_write_reg(client, tmp102_reg[sda->index],
+                                 tmp102_mC_to_reg(val));
+       mutex_unlock(&tmp102->lock);
+       return status ? : count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
+                         tmp102_set_temp, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
+                         tmp102_set_temp, 2);
+
+static struct attribute *tmp102_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group tmp102_attr_group = {
+       .attrs = tmp102_attributes,
+};
+
+#define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
+#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)
+
+static int __devinit tmp102_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct tmp102 *tmp102;
+       int status;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_err(&client->dev, "adapter doesnt support SMBus word "
+                       "transactions\n");
+               return -ENODEV;
+       }
+
+       tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
+       if (!tmp102) {
+               dev_dbg(&client->dev, "kzalloc failed\n");
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(client, tmp102);
+
+       status = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (status < 0) {
+               dev_err(&client->dev, "error reading config register\n");
+               goto fail_free;
+       }
+       tmp102->config_orig = status;
+       status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
+       if (status < 0) {
+               dev_err(&client->dev, "error writing config register\n");
+               goto fail_restore_config;
+       }
+       status = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (status < 0) {
+               dev_err(&client->dev, "error reading config register\n");
+               goto fail_restore_config;
+       }
+       status &= ~TMP102_CONFIG_RD_ONLY;
+       if (status != TMP102_CONFIG) {
+               dev_err(&client->dev, "config settings did not stick\n");
+               status = -ENODEV;
+               goto fail_restore_config;
+       }
+       tmp102->last_update = jiffies - HZ;
+       mutex_init(&tmp102->lock);
+
+       status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
+       if (status) {
+               dev_dbg(&client->dev, "could not create sysfs files\n");
+               goto fail_restore_config;
+       }
+       tmp102->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(tmp102->hwmon_dev)) {
+               dev_dbg(&client->dev, "unable to register hwmon device\n");
+               status = PTR_ERR(tmp102->hwmon_dev);
+               goto fail_remove_sysfs;
+       }
+
+       dev_info(&client->dev, "initialized\n");
+
+       return 0;
+
+fail_remove_sysfs:
+       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
+fail_restore_config:
+       tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig);
+fail_free:
+       i2c_set_clientdata(client, NULL);
+       kfree(tmp102);
+
+       return status;
+}
+
+static int __devexit tmp102_remove(struct i2c_client *client)
+{
+       struct tmp102 *tmp102 = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(tmp102->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
+
+       /* Stop monitoring if device was stopped originally */
+       if (tmp102->config_orig & TMP102_CONF_SD) {
+               int config;
+
+               config = tmp102_read_reg(client, TMP102_CONF_REG);
+               if (config >= 0)
+                       tmp102_write_reg(client, TMP102_CONF_REG,
+                                        config | TMP102_CONF_SD);
+       }
+
+       i2c_set_clientdata(client, NULL);
+       kfree(tmp102);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tmp102_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int config;
+
+       config = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (config < 0)
+               return config;
+
+       config |= TMP102_CONF_SD;
+       return tmp102_write_reg(client, TMP102_CONF_REG, config);
+}
+
+static int tmp102_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int config;
+
+       config = tmp102_read_reg(client, TMP102_CONF_REG);
+       if (config < 0)
+               return config;
+
+       config &= ~TMP102_CONF_SD;
+       return tmp102_write_reg(client, TMP102_CONF_REG, config);
+}
+
+static const struct dev_pm_ops tmp102_dev_pm_ops = {
+       .suspend        = tmp102_suspend,
+       .resume         = tmp102_resume,
+};
+
+#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
+#else
+#define        TMP102_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id tmp102_id[] = {
+       { "tmp102", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp102_id);
+
+static struct i2c_driver tmp102_driver = {
+       .driver.name    = DRIVER_NAME,
+       .driver.pm      = TMP102_DEV_PM_OPS,
+       .probe          = tmp102_probe,
+       .remove         = __devexit_p(tmp102_remove),
+       .id_table       = tmp102_id,
+};
+
+static int __init tmp102_init(void)
+{
+       return i2c_add_driver(&tmp102_driver);
+}
+module_init(tmp102_init);
+
+static void __exit tmp102_exit(void)
+{
+       i2c_del_driver(&tmp102_driver);
+}
+module_exit(tmp102_exit);
+
+MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
+MODULE_LICENSE("GPL");
index d14a1af..ad8d535 100644 (file)
@@ -92,17 +92,6 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2]           = { 0x33, 0x37 };
 #define TMP411_DEVICE_ID                       0x12
 
 /*
- * Functions declarations
- */
-
-static int tmp401_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id);
-static int tmp401_detect(struct i2c_client *client,
-                        struct i2c_board_info *info);
-static int tmp401_remove(struct i2c_client *client);
-static struct tmp401_data *tmp401_update_device(struct device *dev);
-
-/*
  * Driver data (common to all clients)
  */
 
@@ -113,18 +102,6 @@ static const struct i2c_device_id tmp401_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tmp401_id);
 
-static struct i2c_driver tmp401_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "tmp401",
-       },
-       .probe          = tmp401_probe,
-       .remove         = tmp401_remove,
-       .id_table       = tmp401_id,
-       .detect         = tmp401_detect,
-       .address_list   = normal_i2c,
-};
-
 /*
  * Client data (each client gets its own)
  */
@@ -194,6 +171,71 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
        return (temp + 500) / 1000;
 }
 
+static struct tmp401_data *tmp401_update_device_reg16(
+       struct i2c_client *client, struct tmp401_data *data)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               /*
+                * High byte must be read first immediately followed
+                * by the low byte
+                */
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_MSB[i]) << 8;
+               data->temp[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LSB[i]);
+               data->temp_low[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
+               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
+               data->temp_high[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
+               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
+               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_CRIT_LIMIT[i]);
+
+               if (data->kind == tmp411) {
+                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
+                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
+                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_LOWEST_LSB[i]);
+
+                       data->temp_highest[i] = i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
+                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_LSB[i]);
+               }
+       }
+       return data;
+}
+
+static struct tmp401_data *tmp401_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+               data->config = i2c_smbus_read_byte_data(client,
+                                               TMP401_CONFIG_READ);
+               tmp401_update_device_reg16(client, data);
+
+               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_CRIT_HYST);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
 static ssize_t show_temp_value(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
@@ -420,30 +462,36 @@ static ssize_t reset_temp_history(struct device *dev,
 }
 
 static struct sensor_device_attribute tmp401_attr[] = {
-       SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
-       SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0),
-       SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
-       SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0),
-       SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst,
+       SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
+       SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   store_temp_min, 0),
+       SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   store_temp_max, 0),
+       SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+                   store_temp_crit, 0),
+       SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
                    store_temp_crit_hyst, 0),
-       SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_LOW),
-       SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_HIGH),
-       SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_LOCAL_CRIT),
-       SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
-       SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1),
-       SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
-       SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1),
-       SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1),
-       SENSOR_ATTR(temp2_fault, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
+       SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+                   store_temp_min, 1),
+       SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+                   store_temp_max, 1),
+       SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+                   store_temp_crit, 1),
+       SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
+       SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_OPEN),
-       SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_LOW),
-       SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_HIGH),
-       SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL,
+       SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
                    TMP401_STATUS_REMOTE_CRIT),
 };
 
@@ -455,11 +503,11 @@ static struct sensor_device_attribute tmp401_attr[] = {
  * and remote channels.
  */
 static struct sensor_device_attribute tmp411_attr[] = {
-       SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0),
-       SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0),
-       SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1),
-       SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1),
-       SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0),
+       SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
+       SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
+       SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
+       SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
+       SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
 };
 
 /*
@@ -529,6 +577,27 @@ static int tmp401_detect(struct i2c_client *client,
        return 0;
 }
 
+static int tmp401_remove(struct i2c_client *client)
+{
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
+               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
+                       device_remove_file(&client->dev,
+                                          &tmp411_attr[i].dev_attr);
+       }
+
+       kfree(data);
+       return 0;
+}
+
 static int tmp401_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -581,91 +650,17 @@ exit_remove:
        return err;
 }
 
-static int tmp401_remove(struct i2c_client *client)
-{
-       struct tmp401_data *data = i2c_get_clientdata(client);
-       int i;
-
-       if (data->hwmon_dev)
-               hwmon_device_unregister(data->hwmon_dev);
-
-       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
-               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
-
-       if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
-                       device_remove_file(&client->dev,
-                                          &tmp411_attr[i].dev_attr);
-       }
-
-       kfree(data);
-       return 0;
-}
-
-static struct tmp401_data *tmp401_update_device_reg16(
-       struct i2c_client *client, struct tmp401_data *data)
-{
-       int i;
-
-       for (i = 0; i < 2; i++) {
-               /*
-                * High byte must be read first immediately followed
-                * by the low byte
-                */
-               data->temp[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_MSB[i]) << 8;
-               data->temp[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LSB[i]);
-               data->temp_low[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
-               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
-               data->temp_high[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
-               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
-               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
-                       TMP401_TEMP_CRIT_LIMIT[i]);
-
-               if (data->kind == tmp411) {
-                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
-                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
-                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_LOWEST_LSB[i]);
-
-                       data->temp_highest[i] = i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
-                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
-                               client, TMP411_TEMP_HIGHEST_LSB[i]);
-               }
-       }
-       return data;
-}
-
-static struct tmp401_data *tmp401_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tmp401_data *data = i2c_get_clientdata(client);
-
-       mutex_lock(&data->update_lock);
-
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
-               data->config = i2c_smbus_read_byte_data(client,
-                                               TMP401_CONFIG_READ);
-               tmp401_update_device_reg16(client, data);
-
-               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
-                                               TMP401_TEMP_CRIT_HYST);
-
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-
-       mutex_unlock(&data->update_lock);
-
-       return data;
-}
+static struct i2c_driver tmp401_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "tmp401",
+       },
+       .probe          = tmp401_probe,
+       .remove         = tmp401_remove,
+       .id_table       = tmp401_id,
+       .detect         = tmp401_detect,
+       .address_list   = normal_i2c,
+};
 
 static int __init tmp401_init(void)
 {
index 3da73f5..2c60f1f 100644 (file)
@@ -248,6 +248,8 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
 int acpi_check_mem_region(resource_size_t start, resource_size_t n,
                      const char *name);
 
+int acpi_resources_are_enforced(void);
+
 #ifdef CONFIG_PM_SLEEP
 void __init acpi_no_s4_hw_signature(void);
 void __init acpi_old_suspend_ordering(void);