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
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c