]> err.no Git - linux-2.6/blobdiff - drivers/hwmon/lm85.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / drivers / hwmon / lm85.c
index 6229e7d488cbe102bd043683bd7c38f4a5e9ade9..ee5eca1c1921d9d1f7ba1d67bd638ed9d6ba2cb2 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
@@ -123,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
 #define        EMC6D102_REG_EXTEND_ADC3        0x87
 #define        EMC6D102_REG_EXTEND_ADC4        0x88
 
-#define        LM85_ALARM_IN0                  0x0001
-#define        LM85_ALARM_IN1                  0x0002
-#define        LM85_ALARM_IN2                  0x0004
-#define        LM85_ALARM_IN3                  0x0008
-#define        LM85_ALARM_TEMP1                0x0010
-#define        LM85_ALARM_TEMP2                0x0020
-#define        LM85_ALARM_TEMP3                0x0040
-#define        LM85_ALARM_ALARM2               0x0080
-#define        LM85_ALARM_IN4                  0x0100
-#define        LM85_ALARM_RESERVED             0x0200
-#define        LM85_ALARM_FAN1                 0x0400
-#define        LM85_ALARM_FAN2                 0x0800
-#define        LM85_ALARM_FAN3                 0x1000
-#define        LM85_ALARM_FAN4                 0x2000
-#define        LM85_ALARM_TEMP1_FAULT          0x4000
-#define        LM85_ALARM_TEMP3_FAULT          0x8000
-
 
 /* Conversions. Rounding and limit checking is only done on the TO_REG 
    variants. Note that you should be a bit careful with which arguments
@@ -156,22 +139,26 @@ static int lm85_scaling[] = {  /* .001 Volts */
 #define INS_TO_REG(n,val)      \
                SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
 
-#define INSEXT_FROM_REG(n,val,ext,scale)       \
-               SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+#define INSEXT_FROM_REG(n,val,ext)     \
+               SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
 
-#define INS_FROM_REG(n,val)   INSEXT_FROM_REG(n,val,0,1)
+#define INS_FROM_REG(n,val)    SCALE((val), 192, lm85_scaling[n])
 
 /* FAN speed is measured using 90kHz clock */
-#define FAN_TO_REG(val)                (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
+static inline u16 FAN_TO_REG(unsigned long val)
+{
+       if (!val)
+               return 0xffff;
+       return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+}
 #define FAN_FROM_REG(val)      ((val)==0?-1:(val)==0xffff?0:5400000/(val))
 
 /* Temperature is reported in .001 degC increments */
 #define TEMP_TO_REG(val)       \
                SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
-#define TEMPEXT_FROM_REG(val,ext,scale)        \
-               SCALE((val)*scale + (ext),scale,1000)
-#define TEMP_FROM_REG(val)     \
-               TEMPEXT_FROM_REG(val,0,1)
+#define TEMPEXT_FROM_REG(val,ext)      \
+               SCALE(((val) << 4) + (ext), 16, 1000)
+#define TEMP_FROM_REG(val)     ((val) * 1000)
 
 #define PWM_TO_REG(val)                        (SENSORS_LIMIT(val,0,255))
 #define PWM_FROM_REG(val)              (val)
@@ -205,23 +192,20 @@ static int RANGE_TO_REG( int range )
 {
        int i;
 
-       if ( range < lm85_range_map[0] ) { 
-               return 0 ;
-       } else if ( range > lm85_range_map[15] ) {
+       if (range >= lm85_range_map[15])
                return 15 ;
-       } else {  /* find closest match */
-               for ( i = 14 ; i >= 0 ; --i ) {
-                       if ( range > lm85_range_map[i] ) { /* range bracketed */
-                               if ((lm85_range_map[i+1] - range) < 
-                                       (range - lm85_range_map[i])) {
-                                       i++;
-                                       break;
-                               }
-                               break;
-                       }
+
+       /* Find the closest match */
+       for (i = 14; i >= 0; --i) {
+               if (range >= lm85_range_map[i]) {
+                       if ((lm85_range_map[i + 1] - range) <
+                                       (range - lm85_range_map[i]))
+                               return i + 1;
+                       return i;
                }
        }
-       return( i & 0x0f );
+
+       return 0;
 }
 #define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
 
@@ -351,7 +335,6 @@ struct lm85_data {
        u8 tach_mode;           /* Register encoding, combined */
        u8 temp_ext[3];         /* Decoded values */
        u8 in_ext[8];           /* Decoded values */
-       u8 adc_scale;           /* ADC Extended bits scaling factor */
        u8 fan_ppr;             /* Register value */
        u8 smooth[3];           /* Register encoding */
        u8 vid;                 /* Register value */
@@ -381,7 +364,6 @@ static struct i2c_driver lm85_driver = {
        .driver = {
                .name   = "lm85",
        },
-       .id             = I2C_DRIVERID_LM85,
        .attach_adapter = lm85_attach_adapter,
        .detach_client  = lm85_detach_client,
 };
@@ -410,7 +392,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
        int nr = to_sensor_dev_attr(attr)->index;
        struct i2c_client *client = to_i2c_client(dev);
        struct lm85_data *data = i2c_get_clientdata(client);
-       long val = simple_strtol(buf, NULL, 10);
+       unsigned long val = simple_strtoul(buf, NULL, 10);
 
        mutex_lock(&data->update_lock);
        data->fan_min[nr] = FAN_TO_REG(val);
@@ -452,18 +434,14 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 
 static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct lm85_data *data = lm85_update_device(dev);
+       struct lm85_data *data = dev_get_drvdata(dev);
        return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 
 static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct lm85_data *data = i2c_get_clientdata(client);
-       u32 val;
-
-       val = simple_strtoul(buf, NULL, 10);
-       data->vrm = val;
+       struct lm85_data *data = dev_get_drvdata(dev);
+       data->vrm = simple_strtoul(buf, NULL, 10);
        return count;
 }
 
@@ -477,6 +455,32 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr
 
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct lm85_data *data = lm85_update_device(dev);
+       return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13);
+
 /* pwm */
 
 static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
@@ -507,17 +511,64 @@ static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
 {
        int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
-       int     pwm_zone;
+       int pwm_zone, enable;
 
        pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
-       return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) );
+       switch (pwm_zone) {
+       case -1:        /* PWM is always at 100% */
+               enable = 0;
+               break;
+       case 0:         /* PWM is always at 0% */
+       case -2:        /* PWM responds to manual control */
+               enable = 1;
+               break;
+       default:        /* PWM in automatic mode */
+               enable = 2;
+       }
+       return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
+               *attr, const char *buf, size_t count)
+{
+       int nr = to_sensor_dev_attr(attr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm85_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       u8 config;
+
+       switch (val) {
+       case 0:
+               config = 3;
+               break;
+       case 1:
+               config = 7;
+               break;
+       case 2:
+               /* Here we have to choose arbitrarily one of the 5 possible
+                  configurations; I go for the safest */
+               config = 6;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->autofan[nr].config = lm85_read_value(client,
+               LM85_REG_AFAN_CONFIG(nr));
+       data->autofan[nr].config = (data->autofan[nr].config & ~0xe0)
+               | (config << 5);
+       lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
+               data->autofan[nr].config);
+       mutex_unlock(&data->update_lock);
+       return count;
 }
 
 #define show_pwm_reg(offset)                                           \
 static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,              \
                show_pwm, set_pwm, offset - 1);                         \
-static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO,               \
-               show_pwm_enable, NULL, offset - 1)
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,     \
+               show_pwm_enable, set_pwm_enable, offset - 1)
 
 show_pwm_reg(1);
 show_pwm_reg(2);
@@ -532,8 +583,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr,
                                                     data->in[nr],
-                                                    data->in_ext[nr],
-                                                    data->adc_scale) );
+                                                    data->in_ext[nr]));
 }
 
 static ssize_t show_in_min(struct device *dev,  struct device_attribute *attr,
@@ -607,8 +657,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
        int nr = to_sensor_dev_attr(attr)->index;
        struct lm85_data *data = lm85_update_device(dev);
        return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
-                                                   data->temp_ext[nr],
-                                                   data->adc_scale) );
+                                                   data->temp_ext[nr]));
 }
 
 static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
@@ -966,6 +1015,10 @@ static struct attribute *lm85_attributes[] = {
        &sensor_dev_attr_fan2_min.dev_attr.attr,
        &sensor_dev_attr_fan3_min.dev_attr.attr,
        &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan4_alarm.dev_attr.attr,
 
        &sensor_dev_attr_pwm1.dev_attr.attr,
        &sensor_dev_attr_pwm2.dev_attr.attr,
@@ -986,6 +1039,10 @@ static struct attribute *lm85_attributes[] = {
        &sensor_dev_attr_in1_max.dev_attr.attr,
        &sensor_dev_attr_in2_max.dev_attr.attr,
        &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
 
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -996,6 +1053,11 @@ static struct attribute *lm85_attributes[] = {
        &sensor_dev_attr_temp1_max.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
        &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
 
        &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
        &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
@@ -1037,6 +1099,7 @@ static struct attribute *lm85_attributes_in4[] = {
        &sensor_dev_attr_in4_input.dev_attr.attr,
        &sensor_dev_attr_in4_min.dev_attr.attr,
        &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
        NULL
 };
 
@@ -1054,6 +1117,9 @@ static struct attribute *lm85_attributes_in567[] = {
        &sensor_dev_attr_in5_max.dev_attr.attr,
        &sensor_dev_attr_in6_max.dev_attr.attr,
        &sensor_dev_attr_in7_max.dev_attr.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
        NULL
 };
 
@@ -1368,6 +1434,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                
                /* Have to read extended bits first to "freeze" the
                 * more significant bits that are read later.
+                * There are 2 additional resolution bits per channel and we
+                * have room for 4, so we shift them to the left.
                 */
                if ( (data->type == adm1027) || (data->type == adt7463) ) {
                        int ext1 = lm85_read_value(client,
@@ -1377,18 +1445,12 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                        int val = (ext1 << 8) + ext2;
 
                        for(i = 0; i <= 4; i++)
-                               data->in_ext[i] = (val>>(i * 2))&0x03;
+                               data->in_ext[i] = ((val>>(i * 2))&0x03) << 2;
 
                        for(i = 0; i <= 2; i++)
-                               data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
+                               data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c;
                }
 
-               /* adc_scale is 2^(number of LSBs). There are 4 extra bits in
-                  the emc6d102 and 2 in the adt7463 and adm1027. In all
-                  other chips ext is always 0 and the value of scale is
-                  irrelevant. So it is left in 4*/
-               data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
-
                data->vid = lm85_read_value(client, LM85_REG_VID);
 
                for (i = 0; i <= 3; ++i) {