]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'quilt/jdelvare-hwmon'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Dec 2011 03:17:30 +0000 (14:17 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Dec 2011 03:17:30 +0000 (14:17 +1100)
Documentation/hwmon/lm63
drivers/hwmon/Kconfig
drivers/hwmon/coretemp.c
drivers/hwmon/lm63.c
drivers/hwmon/max1111.c

index b9843eab1afb107d6ffb13239b6df435bd7c8c54..af3e8b0ad9c4ad6ff2f4f5aa7e5f4d7e52c16c71 100644 (file)
@@ -12,6 +12,11 @@ Supported chips:
     Addresses scanned: I2C 0x18 and 0x4e
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/pf/LM/LM64.html
+  * National Semiconductor LM96163
+    Prefix: 'lm96163'
+    Addresses scanned: I2C 0x4c
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/pf/LM/LM96163.html
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -62,3 +67,6 @@ values.
 
 The LM64 is effectively an LM63 with GPIO lines. The driver does not
 support these GPIO lines at present.
+
+The LM96163 is an enhanced version of LM63 with improved temperature accuracy
+and better PWM resolution.
index 91be41f6080947936bdd355f25500397ecfd1dfe..50954a454595c39dbda01b0094db025a950dd77e 100644 (file)
@@ -515,11 +515,11 @@ config SENSORS_LINEAGE
          will be called lineage-pem.
 
 config SENSORS_LM63
-       tristate "National Semiconductor LM63 and LM64"
+       tristate "National Semiconductor LM63 and compatibles"
        depends on I2C
        help
          If you say yes here you get support for the National
-         Semiconductor LM63 and LM64 remote diode digital temperature
+         Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
          sensors with integrated fan control.  Such chips are found
          on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
          others.
index 104b3767516cb91b95d310a52c0968adf0d2c639..54c149d4f753341ede2fc580299fb258a00c29b0 100644 (file)
@@ -191,7 +191,8 @@ static ssize_t show_temp(struct device *dev,
        return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
 }
 
-static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
+                                 struct device *dev)
 {
        /* The 100C is default for both mobile and non mobile CPUs */
 
@@ -285,7 +286,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return tjmax;
 }
 
-static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
+                              struct device *dev)
 {
        int err;
        u32 eax, edx;
@@ -324,7 +326,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
        return adjust_tjmax(c, id, dev);
 }
 
-static int create_name_attr(struct platform_data *pdata, struct device *dev)
+static int __devinit create_name_attr(struct platform_data *pdata,
+                                     struct device *dev)
 {
        sysfs_attr_init(&pdata->name_attr.attr);
        pdata->name_attr.attr.name = "name";
@@ -333,8 +336,8 @@ static int create_name_attr(struct platform_data *pdata, struct device *dev)
        return device_create_file(dev, &pdata->name_attr);
 }
 
-static int create_core_attrs(struct temp_data *tdata, struct device *dev,
-                               int attr_no)
+static int __cpuinit create_core_attrs(struct temp_data *tdata,
+                                      struct device *dev, int attr_no)
 {
        int err, i;
        static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
@@ -384,7 +387,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
        return 0;
 }
 
-static struct platform_device *coretemp_get_pdev(unsigned int cpu)
+static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu)
 {
        u16 phys_proc_id = TO_PHYS_ID(cpu);
        struct pdev_entry *p;
@@ -401,7 +404,8 @@ static struct platform_device *coretemp_get_pdev(unsigned int cpu)
        return NULL;
 }
 
-static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
+static struct temp_data __cpuinit *init_temp_data(unsigned int cpu,
+                                                 int pkg_flag)
 {
        struct temp_data *tdata;
 
@@ -419,7 +423,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
        return tdata;
 }
 
-static int create_core_data(struct platform_device *pdev,
+static int __cpuinit create_core_data(struct platform_device *pdev,
                                unsigned int cpu, int pkg_flag)
 {
        struct temp_data *tdata;
@@ -490,7 +494,7 @@ exit_free:
        return err;
 }
 
-static void coretemp_add_core(unsigned int cpu, int pkg_flag)
+static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag)
 {
        struct platform_device *pdev = coretemp_get_pdev(cpu);
        int err;
@@ -619,7 +623,7 @@ exit:
        return err;
 }
 
-static void coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p, *n;
        u16 phys_proc_id = TO_PHYS_ID(cpu);
@@ -635,7 +639,7 @@ static void coretemp_device_remove(unsigned int cpu)
        mutex_unlock(&pdev_list_mutex);
 }
 
-static bool is_any_core_online(struct platform_data *pdata)
+static bool __cpuinit is_any_core_online(struct platform_data *pdata)
 {
        int i;
 
index 508cb291f71bfc35681bfda50dbad88a1a8a8dc2..3d882c93b46d48aa546789c1037ec832ba08d20d 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/types.h>
 
 /*
  * Addresses to scan
@@ -91,6 +92,8 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 #define LM63_REG_MAN_ID                        0xFE
 #define LM63_REG_CHIP_ID               0xFF
 
+#define LM96163_REG_CONFIG_ENHANCED    0x45
+
 /*
  * Conversions and various macros
  * For tachometer counts, the LM63 uses 16-bit values.
@@ -134,7 +137,7 @@ 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 };
+enum chips { lm63, lm64, lm96163 };
 
 /*
  * Driver data (common to all clients)
@@ -143,6 +146,7 @@ enum chips { lm63, lm64 };
 static const struct i2c_device_id lm63_id[] = {
        { "lm63", lm63 },
        { "lm64", lm64 },
+       { "lm96163", lm96163 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -180,11 +184,13 @@ struct lm63_data {
        s8 temp8[3];    /* 0: local input
                           1: local high limit
                           2: remote critical limit */
-       s16 temp11[3];  /* 0: remote input
+       s16 temp11[4];  /* 0: remote input
                           1: remote low limit
-                          2: remote high limit */
+                          2: remote high limit
+                          3: remote offset */
        u8 temp2_crit_hyst;
        u8 alarms;
+       bool pwm_highres;
 };
 
 /*
@@ -204,7 +210,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       unsigned long val = simple_strtoul(buf, NULL, 10);
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->fan[1] = FAN_TO_REG(val);
@@ -220,9 +231,16 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
                         char *buf)
 {
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
+       int pwm;
+
+       if (data->pwm_highres)
+               pwm = data->pwm1_value;
+       else
+               pwm = data->pwm1_value >= 2 * data->pwm1_freq ?
                       255 : (data->pwm1_value * 255 + data->pwm1_freq) /
-                      (2 * data->pwm1_freq));
+                      (2 * data->pwm1_freq);
+
+       return sprintf(buf, "%d\n", pwm);
 }
 
 static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
@@ -231,22 +249,26 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
        unsigned long val;
-       
+       int err;
+
        if (!(data->config_fan & 0x20)) /* register is read-only */
                return -EPERM;
 
-       val = simple_strtoul(buf, NULL, 10);
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+
+       val = SENSORS_LIMIT(val, 0, 255);
        mutex_lock(&data->update_lock);
-       data->pwm1_value = val <= 0 ? 0 :
-                          val >= 255 ? 2 * data->pwm1_freq :
+       data->pwm1_value = data->pwm_highres ? val :
                           (val * data->pwm1_freq * 2 + 127) / 255;
        i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
-                               char *buf)
+static ssize_t show_pwm1_enable(struct device *dev,
+                               struct device_attribute *dummy, char *buf)
 {
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
@@ -283,7 +305,12 @@ static ssize_t set_local_temp8(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+       int err;
+
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
 
        mutex_lock(&data->update_lock);
        data->temp8[1] = TEMP8_TO_REG(val);
@@ -304,19 +331,26 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
                          const char *buf, size_t count)
 {
-       static const u8 reg[4] = {
+       static const u8 reg[6] = {
                LM63_REG_REMOTE_LOW_MSB,
                LM63_REG_REMOTE_LOW_LSB,
                LM63_REG_REMOTE_HIGH_MSB,
                LM63_REG_REMOTE_HIGH_LSB,
+               LM63_REG_REMOTE_OFFSET_MSB,
+               LM63_REG_REMOTE_OFFSET_LSB,
        };
 
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+       int err;
        int nr = attr->index;
 
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
+
        mutex_lock(&data->update_lock);
        data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
@@ -327,10 +361,12 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
        return count;
 }
 
-/* Hysteresis register holds a relative value, while we want to present
-   an absolute to user-space */
-static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
-                                   char *buf)
+/*
+ * Hysteresis register holds a relative value, while we want to present
+ * an absolute to user-space
+ */
+static ssize_t show_temp2_crit_hyst(struct device *dev,
+                                   struct device_attribute *dummy, char *buf)
 {
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
@@ -338,16 +374,24 @@ static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute
                       - TEMP8_FROM_REG(data->temp2_crit_hyst));
 }
 
-/* And now the other way around, user-space provides an absolute
-   hysteresis value and we have to store a relative one */
-static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
+/*
+ * And now the other way around, user-space provides an absolute
+ * hysteresis value and we have to store a relative one
+ */
+static ssize_t set_temp2_crit_hyst(struct device *dev,
+                                  struct device_attribute *dummy,
                                   const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       long val;
+       int err;
        long hyst;
 
+       err = kstrtol(buf, 10, &val);
+       if (err)
+               return err;
+
        mutex_lock(&data->update_lock);
        hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
        i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
@@ -389,6 +433,8 @@ static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 1);
 static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 2);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 3);
 /*
  * On LM63, temp2_crit can be set only once, which should be job
  * of the bootloader.
@@ -416,6 +462,7 @@ static struct attribute *lm63_attributes[] = {
        &sensor_dev_attr_temp2_min.dev_attr.attr,
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_offset.dev_attr.attr,
        &sensor_dev_attr_temp2_crit.dev_attr.attr,
        &dev_attr_temp2_crit_hyst.attr,
 
@@ -487,6 +534,8 @@ static int lm63_detect(struct i2c_client *new_client,
                strlcpy(info->type, "lm63", I2C_NAME_SIZE);
        else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
                strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+       else if (chip_id == 0x49 && address == 0x4c)
+               strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
        else
                return -ENODEV;
 
@@ -518,12 +567,13 @@ static int lm63_probe(struct i2c_client *new_client,
        lm63_init_client(new_client);
 
        /* Register sysfs hooks */
-       if ((err = sysfs_create_group(&new_client->dev.kobj,
-                                     &lm63_group)))
+       err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
+       if (err)
                goto exit_free;
        if (data->config & 0x04) { /* tachometer enabled */
-               if ((err = sysfs_create_group(&new_client->dev.kobj,
-                                             &lm63_group_fan1)))
+               err = sysfs_create_group(&new_client->dev.kobj,
+                                        &lm63_group_fan1);
+               if (err)
                        goto exit_remove_files;
        }
 
@@ -544,8 +594,10 @@ exit:
        return err;
 }
 
-/* Idealy we shouldn't have to initialize anything, since the BIOS
-   should have taken care of everything */
+/*
+ * Ideally we shouldn't have to initialize anything, since the BIOS
+ * should have taken care of everything
+ */
 static void lm63_init_client(struct i2c_client *client)
 {
        struct lm63_data *data = i2c_get_clientdata(client);
@@ -567,6 +619,23 @@ static void lm63_init_client(struct i2c_client *client)
        if (data->pwm1_freq == 0)
                data->pwm1_freq = 1;
 
+       /*
+        * For LM96163, check if high resolution PWM is enabled.
+        * Also, check if unsigned temperature format is enabled
+        * and display a warning message if it is.
+        */
+       if (data->kind == lm96163) {
+               u8 config_enhanced
+                 = i2c_smbus_read_byte_data(client,
+                                            LM96163_REG_CONFIG_ENHANCED);
+               if ((config_enhanced & 0x10)
+                   && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
+                       data->pwm_highres = true;
+               if (config_enhanced & 0x08)
+                       dev_warn(&client->dev,
+                                "Unsigned format for High and Crit setpoints enabled but not supported by driver\n");
+       }
+
        /* Show some debug info about the LM63 configuration */
        dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
                (data->config & 0x04) ? "tachometer input" :
@@ -636,6 +705,10 @@ static struct lm63_data *lm63_update_device(struct device *dev)
                                  LM63_REG_REMOTE_HIGH_MSB) << 8)
                                | i2c_smbus_read_byte_data(client,
                                  LM63_REG_REMOTE_HIGH_LSB);
+               data->temp11[3] = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_LSB);
                data->temp8[2] = i2c_smbus_read_byte_data(client,
                                 LM63_REG_REMOTE_TCRIT);
                data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
index c97b78ef911694e0e818a48029ef01c2208b76b9..5586ccab2a6e5a43110096f2b037d3198256ec89 100644 (file)
@@ -106,11 +106,14 @@ static ssize_t show_adc(struct device *dev,
        if (ret < 0)
                return ret;
 
-       return sprintf(buf, "%d\n", ret);
+       /* assume the reference voltage to be 2.048V, with an 8-bit sample,
+        * the LSB weight is 8mV
+        */
+       return sprintf(buf, "%d\n", ret * 8);
 }
 
 #define MAX1111_ADC_ATTR(_id)          \
-       SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id)
+       SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id)
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 static MAX1111_ADC_ATTR(0);
@@ -120,10 +123,10 @@ static MAX1111_ADC_ATTR(3);
 
 static struct attribute *max1111_attributes[] = {
        &dev_attr_name.attr,
-       &sensor_dev_attr_adc0_in.dev_attr.attr,
-       &sensor_dev_attr_adc1_in.dev_attr.attr,
-       &sensor_dev_attr_adc2_in.dev_attr.attr,
-       &sensor_dev_attr_adc3_in.dev_attr.attr,
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
        NULL,
 };