this patch adds proper support for LM96000 (at least
the version I could test with) and provides some
'generic' control of the tachometer monitor mode for
lm85/lm96000 pwm control.

please consider for (mainline) inclusion!

TIA,
Herbert

Signed-off-by: Herbert Poetzl <[EMAIL PROTECTED]>

diff -NurpP --minimal linux-2.6.27-rc8-khali/Documentation/hwmon/lm85 
linux-2.6.27-rc8-khali-lm96k-v0.1/Documentation/hwmon/lm85
--- linux-2.6.27-rc8-khali/Documentation/hwmon/lm85     2008-10-01 
19:39:51.000000000 +0200
+++ linux-2.6.27-rc8-khali-lm96k-v0.1/Documentation/hwmon/lm85  2008-10-01 
20:39:01.000000000 +0200
@@ -189,6 +189,22 @@ Configuration choices:
      -1    PWM always 100%  (full on)
      -2    Manual control (write to 'pwm#' to set)
 
+* PWM Tachometer Monitor Mode
+
+* pwm#_tmm - controls the monitor mode for pwm#
+
+Configuration choices:
+
+   Value     Meaning                                 <min
+  ------  ----------------------------------------  ------
+      0    Traditional tach input monitor             any   
+      1    Traditional tach input monitor            FFFFh
+      2    Most accurate readings                    FFFFh
+      3    Least effect on programmed PWM of Fan     FFFFh
+
+In the default setting, you will get false readings when under 
+minimum detctable RPM, in all other modes FFFFh.
+
 The National LM85's have two vendor specific configuration
 features. Tach. mode and Spinup Control. For more details on these,
 see the LM85 datasheet or Application Note AN-1260. These features
diff -NurpP --minimal linux-2.6.27-rc8-khali/drivers/hwmon/lm85.c 
linux-2.6.27-rc8-khali-lm96k-v0.1/drivers/hwmon/lm85.c
--- linux-2.6.27-rc8-khali/drivers/hwmon/lm85.c 2008-10-01 19:39:51.000000000 
+0200
+++ linux-2.6.27-rc8-khali-lm96k-v0.1/drivers/hwmon/lm85.c      2008-10-01 
20:29:25.000000000 +0200
@@ -39,7 +39,8 @@
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END 
};
 
 /* Insmod parameters */
-I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
+I2C_CLIENT_INSMOD_7(lm85b, lm85c, lm96000, adm1027, adt7463, emc6d100,
+                   emc6d102);
 
 /* The LM85 registers */
 
@@ -67,6 +68,7 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm102
 #define        LM85_VERSTEP_GENERIC            0x60
 #define        LM85_VERSTEP_LM85C              0x60
 #define        LM85_VERSTEP_LM85B              0x62
+#define        LM85_VERSTEP_LM96000            0x69
 #define        LM85_VERSTEP_ADM1027            0x60
 #define        LM85_VERSTEP_ADT7463            0x62
 #define        LM85_VERSTEP_ADT7463C           0x6A
@@ -91,6 +93,8 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm102
 #define        LM85_REG_AFAN_HYST1             0x6d
 #define        LM85_REG_AFAN_HYST2             0x6e
 
+#define        LM85_REG_TACHO_MON_MODE         0x74
+
 #define        ADM1027_REG_EXTEND_ADC1         0x76
 #define        ADM1027_REG_EXTEND_ADC2         0x77
 
@@ -185,11 +189,16 @@ static int RANGE_TO_REG(int range)
 #define RANGE_FROM_REG(val)    lm85_range_map[(val) & 0x0f]
 
 /* These are the PWM frequency encodings */
-static const int lm85_freq_map[8] = { /* 1 Hz */
-       10, 15, 23, 30, 38, 47, 62, 94
+static const int lm85_freq_map[] = { /* 1 Hz */
+       10, 15, 23, 30, 38, 47, 62, 94, 0
 };
-static const int adm1027_freq_map[8] = { /* 1 Hz */
-       11, 15, 22, 29, 35, 44, 59, 88
+static const int lm96000_freq_map[] = { /* 1 Hz */
+       10, 15, 23, 30, 38, 47, 61, 94,
+       22500, 24000, 25700, 25700,
+       27700, 27700, 30000, 30000, 0
+};
+static const int adm1027_freq_map[] = { /* 1 Hz */
+       11, 15, 22, 29, 35, 44, 59, 88, 0
 };
 
 static int FREQ_TO_REG(const int *map, int freq)
@@ -197,7 +206,7 @@ static int FREQ_TO_REG(const int *map, i
        int i;
 
        /* Find the closest match */
-       for (i = 0; i < 7; ++i)
+       for (i = 0; map[i + 1]; i++)
                if (freq <= (map[i] + map[i + 1]) / 2)
                        break;
        return i;
@@ -205,7 +214,13 @@ static int FREQ_TO_REG(const int *map, i
 
 static int FREQ_FROM_REG(const int *map, u8 reg)
 {
-       return map[reg & 0x07];
+       int i;
+
+       for (i = 0; map[i]; i++)
+               if (reg == i)
+                       break;
+
+       return map[i];
 }
 
 /* Since we can't use strings, I'm abusing these numbers
@@ -304,6 +319,7 @@ struct lm85_data {
        u8 temp_ext[3];         /* Decoded values */
        u8 in_ext[8];           /* Decoded values */
        u8 vid;                 /* Register value */
+       u8 tmm;                 /* Register value */
        u8 vrm;                 /* VRM version */
        u32 alarms;             /* Register encoding, combined */
        struct lm85_autofan autofan[3];
@@ -327,6 +343,7 @@ static const struct i2c_device_id lm85_i
        { "lm85", any_chip },
        { "lm85b", lm85b },
        { "lm85c", lm85c },
+       { "lm96000", lm96000 },
        { "emc6d100", emc6d100 },
        { "emc6d101", emc6d100 },
        { "emc6d102", emc6d102 },
@@ -567,7 +584,31 @@ static ssize_t set_pwm_freq(struct devic
        data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
        lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
                (data->zone[nr].range << 4)
-               | data->pwm_freq[nr]);
+               | (data->pwm_freq[nr] & 0x0f));
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_pwm_tmm(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, "%d\n", (data->tmm >> (2*nr)) & 3);
+}
+
+static ssize_t set_pwm_tmm(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);
+       int mask = 3 << (2*nr);
+
+       mutex_lock(&data->update_lock);
+       data->tmm = (data->tmm & ~mask) | ((val & 3) << (2*nr));
+       lm85_write_value(client, LM85_REG_TACHO_MON_MODE, data->tmm);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -578,7 +619,9 @@ static SENSOR_DEVICE_ATTR(pwm##offset, S
 static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,     \
                show_pwm_enable, set_pwm_enable, offset - 1);           \
 static SENSOR_DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR,       \
-               show_pwm_freq, set_pwm_freq, offset - 1)
+               show_pwm_freq, set_pwm_freq, offset - 1);               \
+static SENSOR_DEVICE_ATTR(pwm##offset##_tmm, S_IRUGO | S_IWUSR,                
\
+               show_pwm_tmm, set_pwm_tmm, offset - 1)
 
 
 show_pwm_reg(1);
@@ -886,7 +929,7 @@ static ssize_t set_temp_auto_temp_min(st
                TEMP_FROM_REG(data->zone[nr].limit));
        lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
                ((data->zone[nr].range & 0x0f) << 4)
-               | (data->pwm_freq[nr] & 0x07));
+               | (data->pwm_freq[nr] & 0x0f));
 
 /* Update temp_auto_hyst and temp_auto_off */
        data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG(
@@ -929,7 +972,7 @@ static ssize_t set_temp_auto_temp_max(st
                val - min);
        lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
                ((data->zone[nr].range & 0x0f) << 4)
-               | (data->pwm_freq[nr] & 0x07));
+               | (data->pwm_freq[nr] & 0x0f));
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -999,6 +1042,9 @@ static struct attribute *lm85_attributes
        &sensor_dev_attr_pwm1_freq.dev_attr.attr,
        &sensor_dev_attr_pwm2_freq.dev_attr.attr,
        &sensor_dev_attr_pwm3_freq.dev_attr.attr,
+       &sensor_dev_attr_pwm1_tmm.dev_attr.attr,
+       &sensor_dev_attr_pwm2_tmm.dev_attr.attr,
+       &sensor_dev_attr_pwm3_tmm.dev_attr.attr,
 
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in1_input.dev_attr.attr,
@@ -1145,6 +1191,9 @@ static int lm85_detect(struct i2c_client
                        case LM85_VERSTEP_LM85B:
                                kind = lm85b;
                                break;
+                       case LM85_VERSTEP_LM96000:
+                               kind = lm96000;
+                               break;
                        }
                } else if (company == LM85_COMPANY_ANALOG_DEV) {
                        switch (verstep) {
@@ -1193,6 +1242,9 @@ static int lm85_detect(struct i2c_client
        case lm85c:
                type_name = "lm85c";
                break;
+       case lm96000:
+               type_name = "lm96000";
+               break;
        case adm1027:
                type_name = "adm1027";
                break;
@@ -1237,6 +1289,9 @@ static int lm85_probe(struct i2c_client 
        case emc6d102:
                data->freq_map = adm1027_freq_map;
                break;
+       case lm96000:
+               data->freq_map = lm96000_freq_map;
+               break;
        default:
                data->freq_map = lm85_freq_map;
        }
@@ -1401,6 +1456,9 @@ static struct lm85_data *lm85_update_dev
                            lm85_read_value(client, LM85_REG_PWM(i));
                }
 
+               /* maybe restrict to LM85/LM96000? */
+               data->tmm = lm85_read_value(client, LM85_REG_TACHO_MON_MODE);
+
                data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
 
                if (data->type == emc6d100) {
@@ -1480,7 +1538,7 @@ static struct lm85_data *lm85_update_dev
                        data->autofan[i].config =
                            lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
                        val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
-                       data->pwm_freq[i] = val & 0x07;
+                       data->pwm_freq[i] = val & 0x0f;
                        data->zone[i].range = val >> 4;
                        data->autofan[i].min_pwm =
                            lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));

_______________________________________________
i2c mailing list
i2c@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/i2c

Reply via email to