* [RFC PATCH v2 0/3] hwmon: (adt7475) small enhancements
@ 2017-05-03 0:40 Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 1/3] hwmon: (adt7475) replace find_nearest() with find_closest() Chris Packham
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-03 0:40 UTC (permalink / raw)
To: linux, linux-hwmon, jdelvare
This is a series of small enhancements to the adt7475 driver. We're using an
adt7476 chip in several network switches and generally speaking the
requirement for this type of equipment is to keep the fan moving so that we
know it is working when we need it.
Chris Packham (3):
hwmon: (adt7475) replace find_nearest() with find_closest()
hwmon: (adt7475) fan stall prevention
hwmon: (adt7475) temperature smoothing
Documentation/hwmon/adt7475 | 9 +++
drivers/hwmon/adt7475.c | 149 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 158 insertions(+)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v2 1/3] hwmon: (adt7475) replace find_nearest() with find_closest()
2017-05-03 0:40 [RFC PATCH v2 0/3] hwmon: (adt7475) small enhancements Chris Packham
@ 2017-05-03 0:40 ` Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing Chris Packham
2 siblings, 0 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-03 0:40 UTC (permalink / raw)
To: linux, linux-hwmon, jdelvare; +Cc: Chris Packham, linux-kernel
The adt7475 has had find_nearest() since it's creation in 2009. Since
then find_closest() has been introduced and several drivers have been
updated to use it. Update the adt7475 to use find_closest() and remove
the now unused find_nearest().
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
drivers/hwmon/adt7475.c | 34 +++-------------------------------
1 file changed, 3 insertions(+), 31 deletions(-)
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index c803e3c5fcd4..ec0c43fbcdce 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -22,6 +22,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/jiffies.h>
+#include <linux/util_macros.h>
/* Indexes for the sysfs hooks */
@@ -314,35 +315,6 @@ static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
i2c_smbus_write_byte_data(client, reg, val & 0xFF);
}
-/*
- * Find the nearest value in a table - used for pwm frequency and
- * auto temp range
- */
-static int find_nearest(long val, const int *array, int size)
-{
- int i;
-
- if (val < array[0])
- return 0;
-
- if (val > array[size - 1])
- return size - 1;
-
- for (i = 0; i < size - 1; i++) {
- int a, b;
-
- if (val > array[i + 1])
- continue;
-
- a = val - array[i];
- b = array[i + 1] - val;
-
- return (a <= b) ? i : i + 1;
- }
-
- return 0;
-}
-
static ssize_t show_voltage(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -606,7 +578,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
val -= temp;
/* Find the nearest table entry to what the user wrote */
- val = find_nearest(val, autorange_table, ARRAY_SIZE(autorange_table));
+ val = find_closest(val, autorange_table, ARRAY_SIZE(autorange_table));
data->range[sattr->index] &= ~0xF0;
data->range[sattr->index] |= val << 4;
@@ -864,7 +836,7 @@ static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
if (kstrtol(buf, 10, &val))
return -EINVAL;
- out = find_nearest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table));
+ out = find_closest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table));
mutex_lock(&data->lock);
--
2.11.0.24.ge6920cf
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention
2017-05-03 0:40 [RFC PATCH v2 0/3] hwmon: (adt7475) small enhancements Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 1/3] hwmon: (adt7475) replace find_nearest() with find_closest() Chris Packham
@ 2017-05-03 0:40 ` Chris Packham
2017-05-03 16:10 ` Guenter Roeck
2017-05-03 0:40 ` [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing Chris Packham
2 siblings, 1 reply; 9+ messages in thread
From: Chris Packham @ 2017-05-03 0:40 UTC (permalink / raw)
To: linux, linux-hwmon, jdelvare
Cc: Chris Packham, Jonathan Corbet, linux-doc, linux-kernel
By default adt7475 will stop the fans (pwm duty cycle 0%) when the
temperature drops past Tmin - hysteresis. Some systems want to keep the
fans moving even when the temperature drops so add new sysfs attributes
that configure the enhanced acoustics min 1-3 which allows the fans to
run at the minimum configure pwm duty cycle.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- use pwmN_stall_dis as the attribute name. I think this describes the purpose
pretty well. I went with a new attribute instead of overloading
pwmN_auto_point1_pwm so this doesn't affect existing users.
Documentation/hwmon/adt7475 | 5 +++++
drivers/hwmon/adt7475.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
index 0502f2b464e1..63507402cd4f 100644
--- a/Documentation/hwmon/adt7475
+++ b/Documentation/hwmon/adt7475
@@ -109,6 +109,11 @@ fan speed) is applied. PWM values range from 0 (off) to 255 (full speed).
Fan speed may be set to maximum when the temperature sensor associated with
the PWM control exceeds temp#_max.
+At Tmin - hysteresis the PWM output can either be off (0% duty cycle) or at the
+minimum (i.e. auto_point1_pwm). This behaviour be configured using the
+pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
+A value of 1 means the fans will run at auto_point1_pwm.
+
Notes
-----
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index ec0c43fbcdce..85957324cd85 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -79,6 +79,9 @@
#define REG_TEMP_TRANGE_BASE 0x5F
+#define REG_ENHANCE_ACOUSTICS1 0x62
+#define REG_ENHANCE_ACOUSTICS2 0x63
+
#define REG_PWM_MIN_BASE 0x64
#define REG_TEMP_TMIN_BASE 0x67
@@ -209,6 +212,7 @@ struct adt7475_data {
u8 range[3];
u8 pwmctl[3];
u8 pwmchan[3];
+ u8 enh_acou[2];
u8 vid;
u8 vrm;
@@ -700,6 +704,43 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
i2c_smbus_write_byte_data(client, reg,
data->pwm[sattr->nr][sattr->index]);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+
+static ssize_t show_stall_dis(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ u8 mask = BIT(5 + sattr->index);
+
+ return sprintf(buf, "%d\n", !!(data->enh_acou[0] & mask));
+}
+
+static ssize_t set_stall_dis(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ long val;
+ u8 mask = BIT(5 + sattr->index);
+
+ if (kstrtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ data->enh_acou[0] &= ~mask;
+ if (val)
+ data->enh_acou[0] |= mask;
+
+ i2c_smbus_write_byte_data(client, REG_ENHANCE_ACOUSTICS1,
+ data->enh_acou[0]);
mutex_unlock(&data->lock);
@@ -1028,6 +1069,8 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
+ set_stall_dis, 0, 0);
static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
1);
static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
@@ -1040,6 +1083,8 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
+ set_stall_dis, 0, 1);
static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
2);
static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
@@ -1052,6 +1097,8 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
+ set_stall_dis, 0, 2);
/* Non-standard name, might need revisiting */
static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit);
@@ -1112,12 +1159,14 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_stall_dis.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_stall_dis.dev_attr.attr,
&dev_attr_pwm_use_point2_pwm_at_crit.attr,
NULL,
};
@@ -1136,6 +1185,7 @@ static struct attribute *pwm2_attrs[] = {
&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_stall_dis.dev_attr.attr,
NULL
};
--
2.11.0.24.ge6920cf
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing
2017-05-03 0:40 [RFC PATCH v2 0/3] hwmon: (adt7475) small enhancements Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 1/3] hwmon: (adt7475) replace find_nearest() with find_closest() Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention Chris Packham
@ 2017-05-03 0:40 ` Chris Packham
2017-05-03 8:14 ` Chris Packham
2017-05-03 16:30 ` Guenter Roeck
2 siblings, 2 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-03 0:40 UTC (permalink / raw)
To: linux, linux-hwmon, jdelvare
Cc: Chris Packham, Jonathan Corbet, linux-doc, linux-kernel
When enabled temperature smoothing allows ramping the fan speed over a
configurable period of time instead of jumping to the new speed
instantaneously.
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
---
Changes in v2:
- use a single tempN_smoothing attribute
Documentation/hwmon/adt7475 | 4 ++
drivers/hwmon/adt7475.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+)
diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
index 63507402cd4f..dd6433d819d0 100644
--- a/Documentation/hwmon/adt7475
+++ b/Documentation/hwmon/adt7475
@@ -114,6 +114,10 @@ minimum (i.e. auto_point1_pwm). This behaviour be configured using the
pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
A value of 1 means the fans will run at auto_point1_pwm.
+The responsiveness of the ADT747x to temperature changes can be configured.
+This allows smoothing of the fan speed transition. To set the transition time
+set the value in ms in the temp[1-*]_smoothing sysfs attribute.
+
Notes
-----
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 85957324cd85..41342de6e20c 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -526,6 +526,96 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
return count;
}
+/* Assuming CONFIG6[SLOW] is 0 */
+static const int ad7475_st_map[] = {
+ 37500, 18800, 12500, 7500, 4700, 3100, 1600, 800,
+};
+
+static ssize_t show_temp_st(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ int shift, idx;
+ long val;
+
+ switch (sattr->index) {
+ case 0:
+ shift = 0;
+ idx = 0;
+ break;
+ case 1:
+ shift = 4;
+ idx = 1;
+ break;
+ case 2:
+ shift = 0;
+ idx = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = data->enh_acou[idx] >> shift;
+ if (val & 0x8) {
+ return sprintf(buf, "%d\n", ad7475_st_map[val & 0x7]);
+ } else {
+ return sprintf(buf, "0\n");
+ }
+}
+
+static ssize_t set_temp_st(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned char reg;
+ int shift, idx;
+ ulong val;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ switch (sattr->index) {
+ case 0:
+ reg = REG_ENHANCE_ACOUSTICS1;
+ shift = 0;
+ idx = 0;
+ break;
+ case 1:
+ reg = REG_ENHANCE_ACOUSTICS2;
+ shift = 4;
+ idx = 1;
+ break;
+ case 2:
+ reg = REG_ENHANCE_ACOUSTICS2;
+ shift = 0;
+ idx = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val > 0) {
+ val = find_closest_descending(val, ad7475_st_map,
+ ARRAY_SIZE(ad7475_st_map));
+ val |= 0x8;
+ }
+
+ mutex_lock(&data->lock);
+
+ data->enh_acou[idx] &= ~(0xf << shift);
+ data->enh_acou[idx] |= (val << shift);
+
+ i2c_smbus_write_byte_data(client, reg, data->enh_acou[idx]);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
/*
* Table of autorange values - the user will write the value in millidegrees,
* and we'll convert it
@@ -1008,6 +1098,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 0);
static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
+ set_temp_st, 0, 0);
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
@@ -1024,6 +1116,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 1);
static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
+ set_temp_st, 0, 1);
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
@@ -1041,6 +1135,8 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 2);
static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
+ set_temp_st, 0, 2);
static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
MIN, 0);
@@ -1125,6 +1221,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_smoothing.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
@@ -1134,6 +1231,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_smoothing.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
@@ -1144,6 +1242,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_smoothing.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
--
2.11.0.24.ge6920cf
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing
2017-05-03 0:40 ` [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing Chris Packham
@ 2017-05-03 8:14 ` Chris Packham
2017-05-03 16:30 ` Guenter Roeck
1 sibling, 0 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-03 8:14 UTC (permalink / raw)
To: linux, linux-hwmon, jdelvare; +Cc: Jonathan Corbet, linux-doc, linux-kernel
On 03/05/17 12:40, Chris Packham wrote:
> When enabled temperature smoothing allows ramping the fan speed over a
> configurable period of time instead of jumping to the new speed
> instantaneously.
>
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> Changes in v2:
> - use a single tempN_smoothing attribute
>
> Documentation/hwmon/adt7475 | 4 ++
> drivers/hwmon/adt7475.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 103 insertions(+)
I've had some feedback internally on this patch around making
show_temp_st() smaller and using "enh_acoustics" instead of "enh_acou".
I'll wait for a while to see if there's any more feedback from the list
before sending out v3.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention
2017-05-03 0:40 ` [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention Chris Packham
@ 2017-05-03 16:10 ` Guenter Roeck
2017-05-03 20:44 ` Chris Packham
0 siblings, 1 reply; 9+ messages in thread
From: Guenter Roeck @ 2017-05-03 16:10 UTC (permalink / raw)
To: Chris Packham
Cc: linux-hwmon, jdelvare, Jonathan Corbet, linux-doc, linux-kernel
On Wed, May 03, 2017 at 12:40:08PM +1200, Chris Packham wrote:
> By default adt7475 will stop the fans (pwm duty cycle 0%) when the
> temperature drops past Tmin - hysteresis. Some systems want to keep the
> fans moving even when the temperature drops so add new sysfs attributes
> that configure the enhanced acoustics min 1-3 which allows the fans to
> run at the minimum configure pwm duty cycle.
>
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> Changes in v2:
> - use pwmN_stall_dis as the attribute name. I think this describes the purpose
> pretty well. I went with a new attribute instead of overloading
> pwmN_auto_point1_pwm so this doesn't affect existing users.
>
> Documentation/hwmon/adt7475 | 5 +++++
> drivers/hwmon/adt7475.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 55 insertions(+)
>
> diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
> index 0502f2b464e1..63507402cd4f 100644
> --- a/Documentation/hwmon/adt7475
> +++ b/Documentation/hwmon/adt7475
> @@ -109,6 +109,11 @@ fan speed) is applied. PWM values range from 0 (off) to 255 (full speed).
> Fan speed may be set to maximum when the temperature sensor associated with
> the PWM control exceeds temp#_max.
>
> +At Tmin - hysteresis the PWM output can either be off (0% duty cycle) or at the
> +minimum (i.e. auto_point1_pwm). This behaviour be configured using the
> +pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
That is really an awkward attribute name. I'll have to think about this some
more.
Guenter
> +A value of 1 means the fans will run at auto_point1_pwm.
> +
> Notes
> -----
>
> diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
> index ec0c43fbcdce..85957324cd85 100644
> --- a/drivers/hwmon/adt7475.c
> +++ b/drivers/hwmon/adt7475.c
> @@ -79,6 +79,9 @@
>
> #define REG_TEMP_TRANGE_BASE 0x5F
>
> +#define REG_ENHANCE_ACOUSTICS1 0x62
> +#define REG_ENHANCE_ACOUSTICS2 0x63
> +
> #define REG_PWM_MIN_BASE 0x64
>
> #define REG_TEMP_TMIN_BASE 0x67
> @@ -209,6 +212,7 @@ struct adt7475_data {
> u8 range[3];
> u8 pwmctl[3];
> u8 pwmchan[3];
> + u8 enh_acou[2];
>
> u8 vid;
> u8 vrm;
> @@ -700,6 +704,43 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
> data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
> i2c_smbus_write_byte_data(client, reg,
> data->pwm[sattr->nr][sattr->index]);
> + mutex_unlock(&data->lock);
> +
> + return count;
> +}
> +
> +
> +static ssize_t show_stall_dis(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
> + struct i2c_client *client = to_i2c_client(dev);
> + struct adt7475_data *data = i2c_get_clientdata(client);
> + u8 mask = BIT(5 + sattr->index);
> +
> + return sprintf(buf, "%d\n", !!(data->enh_acou[0] & mask));
> +}
> +
> +static ssize_t set_stall_dis(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
> + struct i2c_client *client = to_i2c_client(dev);
> + struct adt7475_data *data = i2c_get_clientdata(client);
> + long val;
> + u8 mask = BIT(5 + sattr->index);
> +
> + if (kstrtol(buf, 10, &val))
> + return -EINVAL;
> +
> + mutex_lock(&data->lock);
> +
> + data->enh_acou[0] &= ~mask;
> + if (val)
> + data->enh_acou[0] |= mask;
> +
> + i2c_smbus_write_byte_data(client, REG_ENHANCE_ACOUSTICS1,
> + data->enh_acou[0]);
>
> mutex_unlock(&data->lock);
>
> @@ -1028,6 +1069,8 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MIN, 0);
> static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MAX, 0);
> +static SENSOR_DEVICE_ATTR_2(pwm1_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
> + set_stall_dis, 0, 0);
> static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
> 1);
> static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
> @@ -1040,6 +1083,8 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MIN, 1);
> static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MAX, 1);
> +static SENSOR_DEVICE_ATTR_2(pwm2_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
> + set_stall_dis, 0, 1);
> static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
> 2);
> static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
> @@ -1052,6 +1097,8 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MIN, 2);
> static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
> set_pwm, MAX, 2);
> +static SENSOR_DEVICE_ATTR_2(pwm3_stall_dis, S_IRUGO | S_IWUSR, show_stall_dis,
> + set_stall_dis, 0, 2);
>
> /* Non-standard name, might need revisiting */
> static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit);
> @@ -1112,12 +1159,14 @@ static struct attribute *adt7475_attrs[] = {
> &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
> &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
> &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm1_stall_dis.dev_attr.attr,
> &sensor_dev_attr_pwm3.dev_attr.attr,
> &sensor_dev_attr_pwm3_freq.dev_attr.attr,
> &sensor_dev_attr_pwm3_enable.dev_attr.attr,
> &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
> &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
> &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_stall_dis.dev_attr.attr,
> &dev_attr_pwm_use_point2_pwm_at_crit.attr,
> NULL,
> };
> @@ -1136,6 +1185,7 @@ static struct attribute *pwm2_attrs[] = {
> &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
> &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
> &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm2_stall_dis.dev_attr.attr,
> NULL
> };
>
> --
> 2.11.0.24.ge6920cf
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing
2017-05-03 0:40 ` [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing Chris Packham
2017-05-03 8:14 ` Chris Packham
@ 2017-05-03 16:30 ` Guenter Roeck
2017-05-04 1:28 ` Chris Packham
1 sibling, 1 reply; 9+ messages in thread
From: Guenter Roeck @ 2017-05-03 16:30 UTC (permalink / raw)
To: Chris Packham
Cc: linux-hwmon, jdelvare, Jonathan Corbet, linux-doc, linux-kernel
On Wed, May 03, 2017 at 12:40:09PM +1200, Chris Packham wrote:
> When enabled temperature smoothing allows ramping the fan speed over a
> configurable period of time instead of jumping to the new speed
> instantaneously.
>
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> ---
> Changes in v2:
> - use a single tempN_smoothing attribute
>
> Documentation/hwmon/adt7475 | 4 ++
> drivers/hwmon/adt7475.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 103 insertions(+)
>
> diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
> index 63507402cd4f..dd6433d819d0 100644
> --- a/Documentation/hwmon/adt7475
> +++ b/Documentation/hwmon/adt7475
> @@ -114,6 +114,10 @@ minimum (i.e. auto_point1_pwm). This behaviour be configured using the
> pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
> A value of 1 means the fans will run at auto_point1_pwm.
>
> +The responsiveness of the ADT747x to temperature changes can be configured.
> +This allows smoothing of the fan speed transition. To set the transition time
> +set the value in ms in the temp[1-*]_smoothing sysfs attribute.
> +
> Notes
> -----
>
> diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
> index 85957324cd85..41342de6e20c 100644
> --- a/drivers/hwmon/adt7475.c
> +++ b/drivers/hwmon/adt7475.c
> @@ -526,6 +526,96 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
> return count;
> }
>
> +/* Assuming CONFIG6[SLOW] is 0 */
Can you take that into account and calculate a "best fit" based on the
available options ?
> +static const int ad7475_st_map[] = {
> + 37500, 18800, 12500, 7500, 4700, 3100, 1600, 800,
> +};
> +
> +static ssize_t show_temp_st(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
> + struct i2c_client *client = to_i2c_client(dev);
> + struct adt7475_data *data = i2c_get_clientdata(client);
> + int shift, idx;
> + long val;
> +
> + switch (sattr->index) {
> + case 0:
> + shift = 0;
> + idx = 0;
> + break;
> + case 1:
> + shift = 4;
> + idx = 1;
> + break;
> + case 2:
> + shift = 0;
> + idx = 1;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + val = data->enh_acou[idx] >> shift;
> + if (val & 0x8) {
> + return sprintf(buf, "%d\n", ad7475_st_map[val & 0x7]);
> + } else {
> + return sprintf(buf, "0\n");
> + }
> +}
> +
> +static ssize_t set_temp_st(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
> + struct i2c_client *client = to_i2c_client(dev);
> + struct adt7475_data *data = i2c_get_clientdata(client);
> + unsigned char reg;
> + int shift, idx;
> + ulong val;
> +
> + if (kstrtoul(buf, 10, &val))
> + return -EINVAL;
> +
> + switch (sattr->index) {
> + case 0:
> + reg = REG_ENHANCE_ACOUSTICS1;
> + shift = 0;
> + idx = 0;
> + break;
> + case 1:
> + reg = REG_ENHANCE_ACOUSTICS2;
> + shift = 4;
> + idx = 1;
> + break;
> + case 2:
> + reg = REG_ENHANCE_ACOUSTICS2;
> + shift = 0;
> + idx = 1;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (val > 0) {
> + val = find_closest_descending(val, ad7475_st_map,
> + ARRAY_SIZE(ad7475_st_map));
> + val |= 0x8;
> + }
> +
> + mutex_lock(&data->lock);
> +
> + data->enh_acou[idx] &= ~(0xf << shift);
> + data->enh_acou[idx] |= (val << shift);
> +
> + i2c_smbus_write_byte_data(client, reg, data->enh_acou[idx]);
> +
> + mutex_unlock(&data->lock);
> +
> + return count;
> +}
> +
> /*
> * Table of autorange values - the user will write the value in millidegrees,
> * and we'll convert it
> @@ -1008,6 +1098,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
> THERM, 0);
> static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
> set_temp, HYSTERSIS, 0);
> +static SENSOR_DEVICE_ATTR_2(temp1_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
> + set_temp_st, 0, 0);
> static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
> static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
> static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
> @@ -1024,6 +1116,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
> THERM, 1);
> static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
> set_temp, HYSTERSIS, 1);
> +static SENSOR_DEVICE_ATTR_2(temp2_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
> + set_temp_st, 0, 1);
> static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
> static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
> static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
> @@ -1041,6 +1135,8 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
> THERM, 2);
> static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
> set_temp, HYSTERSIS, 2);
> +static SENSOR_DEVICE_ATTR_2(temp3_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
> + set_temp_st, 0, 2);
> static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
> static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
> MIN, 0);
> @@ -1125,6 +1221,7 @@ static struct attribute *adt7475_attrs[] = {
> &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
> &sensor_dev_attr_temp1_crit.dev_attr.attr,
> &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> + &sensor_dev_attr_temp1_smoothing.dev_attr.attr,
> &sensor_dev_attr_temp2_input.dev_attr.attr,
> &sensor_dev_attr_temp2_alarm.dev_attr.attr,
> &sensor_dev_attr_temp2_max.dev_attr.attr,
> @@ -1134,6 +1231,7 @@ static struct attribute *adt7475_attrs[] = {
> &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
> &sensor_dev_attr_temp2_crit.dev_attr.attr,
> &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
> + &sensor_dev_attr_temp2_smoothing.dev_attr.attr,
> &sensor_dev_attr_temp3_input.dev_attr.attr,
> &sensor_dev_attr_temp3_fault.dev_attr.attr,
> &sensor_dev_attr_temp3_alarm.dev_attr.attr,
> @@ -1144,6 +1242,7 @@ static struct attribute *adt7475_attrs[] = {
> &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
> &sensor_dev_attr_temp3_crit.dev_attr.attr,
> &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
> + &sensor_dev_attr_temp3_smoothing.dev_attr.attr,
> &sensor_dev_attr_fan1_input.dev_attr.attr,
> &sensor_dev_attr_fan1_min.dev_attr.attr,
> &sensor_dev_attr_fan1_alarm.dev_attr.attr,
> --
> 2.11.0.24.ge6920cf
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention
2017-05-03 16:10 ` Guenter Roeck
@ 2017-05-03 20:44 ` Chris Packham
0 siblings, 0 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-03 20:44 UTC (permalink / raw)
To: Guenter Roeck
Cc: linux-hwmon, jdelvare, Jonathan Corbet, linux-doc, linux-kernel
On 04/05/17 04:10, Guenter Roeck wrote:
> On Wed, May 03, 2017 at 12:40:08PM +1200, Chris Packham wrote:
>> By default adt7475 will stop the fans (pwm duty cycle 0%) when the
>> temperature drops past Tmin - hysteresis. Some systems want to keep the
>> fans moving even when the temperature drops so add new sysfs attributes
>> that configure the enhanced acoustics min 1-3 which allows the fans to
>> run at the minimum configure pwm duty cycle.
>>
>> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
>> ---
>> Changes in v2:
>> - use pwmN_stall_dis as the attribute name. I think this describes the purpose
>> pretty well. I went with a new attribute instead of overloading
>> pwmN_auto_point1_pwm so this doesn't affect existing users.
>>
>> Documentation/hwmon/adt7475 | 5 +++++
>> drivers/hwmon/adt7475.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 55 insertions(+)
>>
>> diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
>> index 0502f2b464e1..63507402cd4f 100644
>> --- a/Documentation/hwmon/adt7475
>> +++ b/Documentation/hwmon/adt7475
>> @@ -109,6 +109,11 @@ fan speed) is applied. PWM values range from 0 (off) to 255 (full speed).
>> Fan speed may be set to maximum when the temperature sensor associated with
>> the PWM control exceeds temp#_max.
>>
>> +At Tmin - hysteresis the PWM output can either be off (0% duty cycle) or at the
>> +minimum (i.e. auto_point1_pwm). This behaviour be configured using the
>> +pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
>
> That is really an awkward attribute name. I'll have to think about this some
> more.
I agree. The other thing I considered was "halt" and using inverted
logic so halt == 1 reflected the HW default of allowing fans to stop.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing
2017-05-03 16:30 ` Guenter Roeck
@ 2017-05-04 1:28 ` Chris Packham
0 siblings, 0 replies; 9+ messages in thread
From: Chris Packham @ 2017-05-04 1:28 UTC (permalink / raw)
To: Guenter Roeck
Cc: linux-hwmon, jdelvare, Jonathan Corbet, linux-doc, linux-kernel
On 04/05/17 04:30, Guenter Roeck wrote:
> On Wed, May 03, 2017 at 12:40:09PM +1200, Chris Packham wrote:
>> When enabled temperature smoothing allows ramping the fan speed over a
>> configurable period of time instead of jumping to the new speed
>> instantaneously.
>>
>> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
>> ---
>> Changes in v2:
>> - use a single tempN_smoothing attribute
>>
>> Documentation/hwmon/adt7475 | 4 ++
>> drivers/hwmon/adt7475.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 103 insertions(+)
>>
>> diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475
>> index 63507402cd4f..dd6433d819d0 100644
>> --- a/Documentation/hwmon/adt7475
>> +++ b/Documentation/hwmon/adt7475
>> @@ -114,6 +114,10 @@ minimum (i.e. auto_point1_pwm). This behaviour be configured using the
>> pwm[1-*]_stall_dis sysfs attribute. A value of 0 means the fans will shut off.
>> A value of 1 means the fans will run at auto_point1_pwm.
>>
>> +The responsiveness of the ADT747x to temperature changes can be configured.
>> +This allows smoothing of the fan speed transition. To set the transition time
>> +set the value in ms in the temp[1-*]_smoothing sysfs attribute.
>> +
>> Notes
>> -----
>>
>> diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
>> index 85957324cd85..41342de6e20c 100644
>> --- a/drivers/hwmon/adt7475.c
>> +++ b/drivers/hwmon/adt7475.c
>> @@ -526,6 +526,96 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
>> return count;
>> }
>>
>> +/* Assuming CONFIG6[SLOW] is 0 */
>
> Can you take that into account and calculate a "best fit" based on the
> available options ?
Do you mean check CONFIG6[SLOW] and choose between 1 of 2 possible maps?
Or have a unified map and choose both the SLOW and ACOU values?
I briefly considered the latter but things soon started to get
complicated. It would look something like this (please excuse using a
MUA as a code editor).
static const int ad7475_st_map[] = {
52200, 37500, 26100, 18800, 17400, 12500, 10400, 7500,
6500, 4700, 4400, 3100, 2200, 1600, 1100, 800,
};
i = find_closest_descending(val, ad7475_st_map,
ARRAY_SIZE(ad7475_st_map));
acou = i / 2;
slow = i % 2;
Going in reverse then gets really fun
slow = !!(i2c_smbus_read_byte_data(client, REG_CONFIG6) & BIT(PWMx))
acou = data->enh_acou[idx];
i = (acou * 2) + slow;
return sprintf(buf, "%d\n", ad7475_st_map[i]);
I could probably make the above work I just wasn't sure it was worth the
hassle. Only the higher ranges would really be noticeable to anyone.
>
>> +static const int ad7475_st_map[] = {
>> + 37500, 18800, 12500, 7500, 4700, 3100, 1600, 800,
>> +};
>> +
>> +static ssize_t show_temp_st(struct device *dev, struct device_attribute *attr,
>> + char *buf)
>> +{
>> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
>> + struct i2c_client *client = to_i2c_client(dev);
>> + struct adt7475_data *data = i2c_get_clientdata(client);
>> + int shift, idx;
>> + long val;
>> +
>> + switch (sattr->index) {
>> + case 0:
>> + shift = 0;
>> + idx = 0;
>> + break;
>> + case 1:
>> + shift = 4;
>> + idx = 1;
>> + break;
>> + case 2:
>> + shift = 0;
>> + idx = 1;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + val = data->enh_acou[idx] >> shift;
>> + if (val & 0x8) {
>> + return sprintf(buf, "%d\n", ad7475_st_map[val & 0x7]);
>> + } else {
>> + return sprintf(buf, "0\n");
>> + }
>> +}
>> +
>> +static ssize_t set_temp_st(struct device *dev, struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
>> + struct i2c_client *client = to_i2c_client(dev);
>> + struct adt7475_data *data = i2c_get_clientdata(client);
>> + unsigned char reg;
>> + int shift, idx;
>> + ulong val;
>> +
>> + if (kstrtoul(buf, 10, &val))
>> + return -EINVAL;
>> +
>> + switch (sattr->index) {
>> + case 0:
>> + reg = REG_ENHANCE_ACOUSTICS1;
>> + shift = 0;
>> + idx = 0;
>> + break;
>> + case 1:
>> + reg = REG_ENHANCE_ACOUSTICS2;
>> + shift = 4;
>> + idx = 1;
>> + break;
>> + case 2:
>> + reg = REG_ENHANCE_ACOUSTICS2;
>> + shift = 0;
>> + idx = 1;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + if (val > 0) {
>> + val = find_closest_descending(val, ad7475_st_map,
>> + ARRAY_SIZE(ad7475_st_map));
>> + val |= 0x8;
>> + }
>> +
>> + mutex_lock(&data->lock);
>> +
>> + data->enh_acou[idx] &= ~(0xf << shift);
>> + data->enh_acou[idx] |= (val << shift);
>> +
>> + i2c_smbus_write_byte_data(client, reg, data->enh_acou[idx]);
>> +
>> + mutex_unlock(&data->lock);
>> +
>> + return count;
>> +}
>> +
>> /*
>> * Table of autorange values - the user will write the value in millidegrees,
>> * and we'll convert it
>> @@ -1008,6 +1098,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
>> THERM, 0);
>> static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
>> set_temp, HYSTERSIS, 0);
>> +static SENSOR_DEVICE_ATTR_2(temp1_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
>> + set_temp_st, 0, 0);
>> static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
>> static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
>> static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
>> @@ -1024,6 +1116,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
>> THERM, 1);
>> static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
>> set_temp, HYSTERSIS, 1);
>> +static SENSOR_DEVICE_ATTR_2(temp2_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
>> + set_temp_st, 0, 1);
>> static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
>> static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
>> static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
>> @@ -1041,6 +1135,8 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
>> THERM, 2);
>> static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
>> set_temp, HYSTERSIS, 2);
>> +static SENSOR_DEVICE_ATTR_2(temp3_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
>> + set_temp_st, 0, 2);
>> static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
>> static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
>> MIN, 0);
>> @@ -1125,6 +1221,7 @@ static struct attribute *adt7475_attrs[] = {
>> &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
>> &sensor_dev_attr_temp1_crit.dev_attr.attr,
>> &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
>> + &sensor_dev_attr_temp1_smoothing.dev_attr.attr,
>> &sensor_dev_attr_temp2_input.dev_attr.attr,
>> &sensor_dev_attr_temp2_alarm.dev_attr.attr,
>> &sensor_dev_attr_temp2_max.dev_attr.attr,
>> @@ -1134,6 +1231,7 @@ static struct attribute *adt7475_attrs[] = {
>> &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
>> &sensor_dev_attr_temp2_crit.dev_attr.attr,
>> &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
>> + &sensor_dev_attr_temp2_smoothing.dev_attr.attr,
>> &sensor_dev_attr_temp3_input.dev_attr.attr,
>> &sensor_dev_attr_temp3_fault.dev_attr.attr,
>> &sensor_dev_attr_temp3_alarm.dev_attr.attr,
>> @@ -1144,6 +1242,7 @@ static struct attribute *adt7475_attrs[] = {
>> &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
>> &sensor_dev_attr_temp3_crit.dev_attr.attr,
>> &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
>> + &sensor_dev_attr_temp3_smoothing.dev_attr.attr,
>> &sensor_dev_attr_fan1_input.dev_attr.attr,
>> &sensor_dev_attr_fan1_min.dev_attr.attr,
>> &sensor_dev_attr_fan1_alarm.dev_attr.attr,
>> --
>> 2.11.0.24.ge6920cf
>>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-05-04 1:28 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-03 0:40 [RFC PATCH v2 0/3] hwmon: (adt7475) small enhancements Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 1/3] hwmon: (adt7475) replace find_nearest() with find_closest() Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 2/3] hwmon: (adt7475) fan stall prevention Chris Packham
2017-05-03 16:10 ` Guenter Roeck
2017-05-03 20:44 ` Chris Packham
2017-05-03 0:40 ` [RFC PATCH v2 3/3] hwmon: (adt7475) temperature smoothing Chris Packham
2017-05-03 8:14 ` Chris Packham
2017-05-03 16:30 ` Guenter Roeck
2017-05-04 1:28 ` Chris Packham
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.