hwmon: (tmp401) Add support for update_interval attribute
[pandora-kernel.git] / drivers / hwmon / tmp401.c
index c85f696..fa6af51 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
@@ -40,9 +41,9 @@
 #include <linux/sysfs.h>
 
 /* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
 
-enum chips { tmp401, tmp411 };
+enum chips { tmp401, tmp411, tmp431 };
 
 /*
  * The TMP401 registers, note some registers have different addresses for
@@ -54,42 +55,54 @@ enum chips { tmp401, tmp411 };
 #define TMP401_CONVERSION_RATE_READ            0x04
 #define TMP401_CONVERSION_RATE_WRITE           0x0A
 #define TMP401_TEMP_CRIT_HYST                  0x21
-#define TMP401_CONSECUTIVE_ALERT               0x22
 #define TMP401_MANUFACTURER_ID_REG             0xFE
 #define TMP401_DEVICE_ID_REG                   0xFF
-#define TMP411_N_FACTOR_REG                    0x18
-
-static const u8 TMP401_TEMP_MSB[2]                     = { 0x00, 0x01 };
-static const u8 TMP401_TEMP_LSB[2]                     = { 0x15, 0x10 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2]      = { 0x06, 0x08 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2]     = { 0x0C, 0x0E };
-static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2]           = { 0x17, 0x14 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2]     = { 0x05, 0x07 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2]    = { 0x0B, 0x0D };
-static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2]          = { 0x16, 0x13 };
-/* These are called the THERM limit / hysteresis / mask in the datasheet */
-static const u8 TMP401_TEMP_CRIT_LIMIT[2]              = { 0x20, 0x19 };
-
-static const u8 TMP411_TEMP_LOWEST_MSB[2]              = { 0x30, 0x34 };
-static const u8 TMP411_TEMP_LOWEST_LSB[2]              = { 0x31, 0x35 };
-static const u8 TMP411_TEMP_HIGHEST_MSB[2]             = { 0x32, 0x36 };
-static const u8 TMP411_TEMP_HIGHEST_LSB[2]             = { 0x33, 0x37 };
+
+static const u8 TMP401_TEMP_MSB_READ[6][2] = {
+       { 0x00, 0x01 }, /* temp */
+       { 0x06, 0x08 }, /* low limit */
+       { 0x05, 0x07 }, /* high limit */
+       { 0x20, 0x19 }, /* therm (crit) limit */
+       { 0x30, 0x34 }, /* lowest */
+       { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
+       { 0, 0 },       /* temp (unused) */
+       { 0x0C, 0x0E }, /* low limit */
+       { 0x0B, 0x0D }, /* high limit */
+       { 0x20, 0x19 }, /* therm (crit) limit */
+       { 0x30, 0x34 }, /* lowest */
+       { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_LSB[6][2] = {
+       { 0x15, 0x10 }, /* temp */
+       { 0x17, 0x14 }, /* low limit */
+       { 0x16, 0x13 }, /* high limit */
+       { 0, 0 },       /* therm (crit) limit (unused) */
+       { 0x31, 0x35 }, /* lowest */
+       { 0x33, 0x37 }, /* highest */
+};
 
 /* Flags */
-#define TMP401_CONFIG_RANGE            0x04
-#define TMP401_CONFIG_SHUTDOWN         0x40
-#define TMP401_STATUS_LOCAL_CRIT               0x01
-#define TMP401_STATUS_REMOTE_CRIT              0x02
-#define TMP401_STATUS_REMOTE_OPEN              0x04
-#define TMP401_STATUS_REMOTE_LOW               0x08
-#define TMP401_STATUS_REMOTE_HIGH              0x10
-#define TMP401_STATUS_LOCAL_LOW                0x20
-#define TMP401_STATUS_LOCAL_HIGH               0x40
+#define TMP401_CONFIG_RANGE                    BIT(2)
+#define TMP401_CONFIG_SHUTDOWN                 BIT(6)
+#define TMP401_STATUS_LOCAL_CRIT               BIT(0)
+#define TMP401_STATUS_REMOTE_CRIT              BIT(1)
+#define TMP401_STATUS_REMOTE_OPEN              BIT(2)
+#define TMP401_STATUS_REMOTE_LOW               BIT(3)
+#define TMP401_STATUS_REMOTE_HIGH              BIT(4)
+#define TMP401_STATUS_LOCAL_LOW                        BIT(5)
+#define TMP401_STATUS_LOCAL_HIGH               BIT(6)
 
 /* Manufacturer / Device ID's */
 #define TMP401_MANUFACTURER_ID                 0x55
 #define TMP401_DEVICE_ID                       0x11
-#define TMP411_DEVICE_ID                       0x12
+#define TMP411A_DEVICE_ID                      0x12
+#define TMP411B_DEVICE_ID                      0x13
+#define TMP411C_DEVICE_ID                      0x10
+#define TMP431_DEVICE_ID                       0x31
 
 /*
  * Driver data (common to all clients)
@@ -98,6 +111,7 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2]           = { 0x33, 0x37 };
 static const struct i2c_device_id tmp401_id[] = {
        { "tmp401", tmp401 },
        { "tmp411", tmp411 },
+       { "tmp431", tmp431 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, tmp401_id);
@@ -113,16 +127,13 @@ struct tmp401_data {
        unsigned long last_updated; /* in jiffies */
        enum chips kind;
 
+       unsigned int update_interval;   /* in milliseconds */
+
        /* register values */
        u8 status;
        u8 config;
-       u16 temp[2];
-       u16 temp_low[2];
-       u16 temp_high[2];
-       u8 temp_crit[2];
+       u16 temp[6][2];
        u8 temp_crit_hyst;
-       u16 temp_lowest[2];
-       u16 temp_highest[2];
 };
 
 /*
@@ -136,10 +147,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
        if (config & TMP401_CONFIG_RANGE)
                temp -= 64 * 256;
 
-       return (temp * 625 + 80) / 160;
+       return DIV_ROUND_CLOSEST(temp * 125, 32);
 }
 
-static u16 tmp401_temp_to_register(long temp, u8 config)
+static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
 {
        if (config & TMP401_CONFIG_RANGE) {
                temp = clamp_val(temp, -64000, 191000);
@@ -147,134 +158,96 @@ static u16 tmp401_temp_to_register(long temp, u8 config)
        } else
                temp = clamp_val(temp, 0, 127000);
 
-       return (temp * 160 + 312) / 625;
+       return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
 }
 
-static int tmp401_crit_register_to_temp(u8 reg, u8 config)
+static int tmp401_update_device_reg16(struct i2c_client *client,
+                                     struct tmp401_data *data)
 {
-       int temp = reg;
-
-       if (config & TMP401_CONFIG_RANGE)
-               temp -= 64;
-
-       return temp * 1000;
-}
-
-static u8 tmp401_crit_temp_to_register(long temp, u8 config)
-{
-       if (config & TMP401_CONFIG_RANGE) {
-               temp = clamp_val(temp, -64000, 191000);
-               temp += 64000;
-       } else
-               temp = clamp_val(temp, 0, 127000);
-
-       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]);
+       int i, j, val;
+       int num_regs = data->kind == tmp411 ? 6 : 4;
+
+       for (i = 0; i < 2; i++) {                       /* local / rem1 */
+               for (j = 0; j < num_regs; j++) {        /* temp / low / ... */
+                       /*
+                        * High byte must be read first immediately followed
+                        * by the low byte
+                        */
+                       val = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_MSB_READ[j][i]);
+                       if (val < 0)
+                               return val;
+                       data->temp[j][i] = val << 8;
+                       if (j == 3)             /* crit is msb only */
+                               continue;
+                       val = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_LSB[j][i]);
+                       if (val < 0)
+                               return val;
+                       data->temp[j][i] |= val;
                }
        }
-       return data;
+       return 0;
 }
 
 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);
+       struct tmp401_data *ret = data;
+       int val;
+       unsigned long next_update;
 
        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);
+       next_update = data->last_updated +
+                     msecs_to_jiffies(data->update_interval) + 1;
+       if (time_after(jiffies, next_update) || !data->valid) {
+               val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->status = val;
+               val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->config = val;
+               val = tmp401_update_device_reg16(client, data);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
+               if (val < 0) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_crit_hyst = val;
 
                data->last_updated = jiffies;
                data->valid = 1;
        }
 
+abort:
        mutex_unlock(&data->update_lock);
-
-       return data;
+       return ret;
 }
 
-static ssize_t show_temp_value(struct device *dev,
-       struct device_attribute *devattr, char *buf)
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
 {
-       int index = to_sensor_dev_attr(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
 
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp[index], data->config));
-}
-
-static ssize_t show_temp_min(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_low[index], data->config));
-}
-
-static ssize_t show_temp_max(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_high[index], data->config));
-}
-
-static ssize_t show_temp_crit(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-                       tmp401_crit_register_to_temp(data->temp_crit[index],
-                                                       data->config));
+               tmp401_register_to_temp(data->temp[nr][index], data->config));
 }
 
 static ssize_t show_temp_crit_hyst(struct device *dev,
@@ -283,122 +256,58 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
        int temp, index = to_sensor_dev_attr(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
 
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
        mutex_lock(&data->update_lock);
-       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
-                                               data->config);
+       temp = tmp401_register_to_temp(data->temp[3][index], data->config);
        temp -= data->temp_crit_hyst * 1000;
        mutex_unlock(&data->update_lock);
 
        return sprintf(buf, "%d\n", temp);
 }
 
-static ssize_t show_temp_lowest(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_lowest[index],
-                                       data->config));
-}
-
-static ssize_t show_temp_highest(struct device *dev,
-       struct device_attribute *devattr, char *buf)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-
-       return sprintf(buf, "%d\n",
-               tmp401_register_to_temp(data->temp_highest[index],
-                                       data->config));
-}
-
 static ssize_t show_status(struct device *dev,
        struct device_attribute *devattr, char *buf)
 {
        int mask = to_sensor_dev_attr(devattr)->index;
        struct tmp401_data *data = tmp401_update_device(dev);
 
-       if (data->status & mask)
-               return sprintf(buf, "1\n");
-       else
-               return sprintf(buf, "0\n");
-}
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
-static ssize_t store_temp_min(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-       long val;
-       u16 reg;
-
-       if (kstrtol(buf, 10, &val))
-               return -EINVAL;
-
-       reg = tmp401_temp_to_register(val, data->config);
-
-       mutex_lock(&data->update_lock);
-
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
-
-       data->temp_low[index] = reg;
-
-       mutex_unlock(&data->update_lock);
-
-       return count;
+       return sprintf(buf, "%d\n", !!(data->status & mask));
 }
 
-static ssize_t store_temp_max(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
+static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
+                         const char *buf, size_t count)
 {
-       int index = to_sensor_dev_attr(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int index = to_sensor_dev_attr_2(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
        struct tmp401_data *data = tmp401_update_device(dev);
        long val;
        u16 reg;
 
-       if (kstrtol(buf, 10, &val))
-               return -EINVAL;
-
-       reg = tmp401_temp_to_register(val, data->config);
-
-       mutex_lock(&data->update_lock);
-
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
-
-       data->temp_high[index] = reg;
-
-       mutex_unlock(&data->update_lock);
-
-       return count;
-}
-
-static ssize_t store_temp_crit(struct device *dev, struct device_attribute
-       *devattr, const char *buf, size_t count)
-{
-       int index = to_sensor_dev_attr(devattr)->index;
-       struct tmp401_data *data = tmp401_update_device(dev);
-       long val;
-       u8 reg;
+       if (IS_ERR(data))
+               return PTR_ERR(data);
 
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
-       reg = tmp401_crit_temp_to_register(val, data->config);
+       reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
 
        mutex_lock(&data->update_lock);
 
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_CRIT_LIMIT[index], reg);
-
-       data->temp_crit[index] = reg;
+       i2c_smbus_write_byte_data(client,
+                                 TMP401_TEMP_MSB_WRITE[nr][index],
+                                 reg >> 8);
+       if (nr != 3) {
+               i2c_smbus_write_byte_data(client,
+                                         TMP401_TEMP_LSB[nr][index],
+                                         reg & 0xFF);
+       }
+       data->temp[nr][index] = reg;
 
        mutex_unlock(&data->update_lock);
 
@@ -413,6 +322,9 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
        long val;
        u8 reg;
 
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
@@ -422,13 +334,12 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
                val = clamp_val(val, 0, 127000);
 
        mutex_lock(&data->update_lock);
-       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
-                                               data->config);
+       temp = tmp401_register_to_temp(data->temp[3][index], data->config);
        val = clamp_val(val, temp - 255000, temp);
        reg = ((temp - val) + 500) / 1000;
 
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP401_TEMP_CRIT_HYST, reg);
+       i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST,
+                                 reg);
 
        data->temp_crit_hyst = reg;
 
@@ -445,54 +356,130 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
 static ssize_t reset_temp_history(struct device *dev,
        struct device_attribute *devattr, const char *buf, size_t count)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
        long val;
 
        if (kstrtol(buf, 10, &val))
                return -EINVAL;
 
        if (val != 1) {
-               dev_err(dev, "temp_reset_history value %ld not"
-                       " supported. Use 1 to reset the history!\n", val);
+               dev_err(dev,
+                       "temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
+                       val);
                return -EINVAL;
        }
-       i2c_smbus_write_byte_data(to_i2c_client(dev),
-               TMP411_TEMP_LOWEST_MSB[0], val);
+       mutex_lock(&data->update_lock);
+       i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
+       data->valid = 0;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int err, rate;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       /*
+        * For valid rates, interval can be calculated as
+        *      interval = (1 << (7 - rate)) * 125;
+        * Rounded rate is therefore
+        *      rate = 7 - __fls(interval * 4 / (125 * 3));
+        * Use clamp_val() to avoid overflows, and to ensure valid input
+        * for __fls.
+        */
+       val = clamp_val(val, 125, 16000);
+       rate = 7 - __fls(val * 4 / (125 * 3));
+       mutex_lock(&data->update_lock);
+       i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
+       data->update_interval = (1 << (7 - rate)) * 125;
+       mutex_unlock(&data->update_lock);
 
        return count;
 }
 
-static struct sensor_device_attribute tmp401_attr[] = {
-       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, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_LOW),
-       SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_HIGH),
-       SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_LOCAL_CRIT),
-       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, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_LOW),
-       SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_HIGH),
-       SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
-                   TMP401_STATUS_REMOTE_CRIT),
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 3, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+                         show_temp_crit_hyst, store_temp_crit_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_LOCAL_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_LOCAL_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_LOCAL_CRIT);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
+                           store_temp, 3, 1);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+                         NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_REMOTE_OPEN);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_REMOTE_LOW);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_REMOTE_HIGH);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
+                         TMP401_STATUS_REMOTE_CRIT);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+                  set_update_interval);
+
+static struct attribute *tmp401_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+
+       &dev_attr_update_interval.attr,
+
+       NULL
+};
+
+static const struct attribute_group tmp401_group = {
+       .attrs = tmp401_attributes,
 };
 
 /*
@@ -502,12 +489,24 @@ static struct sensor_device_attribute tmp401_attr[] = {
  * minimum and maximum register reset for both the local
  * and remote channels.
  */
-static struct sensor_device_attribute tmp411_attr[] = {
-       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),
+static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
+static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
+                         0);
+
+static struct attribute *tmp411_attributes[] = {
+       &sensor_dev_attr_temp1_highest.dev_attr.attr,
+       &sensor_dev_attr_temp1_lowest.dev_attr.attr,
+       &sensor_dev_attr_temp2_highest.dev_attr.attr,
+       &sensor_dev_attr_temp2_lowest.dev_attr.attr,
+       &sensor_dev_attr_temp_reset_history.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group tmp411_group = {
+       .attrs = tmp411_attributes,
 };
 
 /*
@@ -517,9 +516,11 @@ static struct sensor_device_attribute tmp411_attr[] = {
 static void tmp401_init_client(struct i2c_client *client)
 {
        int config, config_orig;
+       struct tmp401_data *data = i2c_get_clientdata(client);
 
        /* Set the conversion rate to 2 Hz */
        i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+       data->update_interval = 500;
 
        /* Start conversions (disable shutdown if necessary) */
        config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
@@ -554,11 +555,30 @@ static int tmp401_detect(struct i2c_client *client,
 
        switch (reg) {
        case TMP401_DEVICE_ID:
+               if (client->addr != 0x4c)
+                       return -ENODEV;
                kind = tmp401;
                break;
-       case TMP411_DEVICE_ID:
+       case TMP411A_DEVICE_ID:
+               if (client->addr != 0x4c)
+                       return -ENODEV;
+               kind = tmp411;
+               break;
+       case TMP411B_DEVICE_ID:
+               if (client->addr != 0x4d)
+                       return -ENODEV;
+               kind = tmp411;
+               break;
+       case TMP411C_DEVICE_ID:
+               if (client->addr != 0x4e)
+                       return -ENODEV;
                kind = tmp411;
                break;
+       case TMP431_DEVICE_ID:
+               if (client->addr == 0x4e)
+                       return -ENODEV;
+               kind = tmp431;
+               break;
        default:
                return -ENODEV;
        }
@@ -579,20 +599,16 @@ static int tmp401_detect(struct i2c_client *client,
 
 static int tmp401_remove(struct i2c_client *client)
 {
+       struct device *dev = &client->dev;
        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);
+       sysfs_remove_group(&dev->kobj, &tmp401_group);
 
-       if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
-                       device_remove_file(&client->dev,
-                                          &tmp411_attr[i].dev_attr);
-       }
+       if (data->kind == tmp411)
+               sysfs_remove_group(&dev->kobj, &tmp411_group);
 
        return 0;
 }
@@ -600,12 +616,12 @@ static int tmp401_remove(struct i2c_client *client)
 static int tmp401_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
-       int i, err = 0;
+       struct device *dev = &client->dev;
+       int err;
        struct tmp401_data *data;
-       const char *names[] = { "TMP401", "TMP411" };
+       const char *names[] = { "TMP401", "TMP411", "TMP431" };
 
-       data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
-                           GFP_KERNEL);
+       data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -617,31 +633,25 @@ static int tmp401_probe(struct i2c_client *client,
        tmp401_init_client(client);
 
        /* Register sysfs hooks */
-       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
-               err = device_create_file(&client->dev,
-                                        &tmp401_attr[i].dev_attr);
-               if (err)
-                       goto exit_remove;
-       }
+       err = sysfs_create_group(&dev->kobj, &tmp401_group);
+       if (err)
+               return err;
 
        /* Register additional tmp411 sysfs hooks */
        if (data->kind == tmp411) {
-               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
-                       err = device_create_file(&client->dev,
-                                                &tmp411_attr[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
-               }
+               err = sysfs_create_group(&dev->kobj, &tmp411_group);
+               if (err)
+                       goto exit_remove;
        }
 
-       data->hwmon_dev = hwmon_device_register(&client->dev);
+       data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
                data->hwmon_dev = NULL;
                goto exit_remove;
        }
 
-       dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
+       dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
 
        return 0;