summaryrefslogtreecommitdiff
path: root/drivers/hwmon/adt7475.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/adt7475.c')
-rw-r--r--drivers/hwmon/adt7475.c184
1 files changed, 149 insertions, 35 deletions
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index c803e3c5fcd4..1baa213a60bd 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 */
@@ -78,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
@@ -208,6 +212,7 @@ struct adt7475_data {
u8 range[3];
u8 pwmctl[3];
u8 pwmchan[3];
+ u8 enh_acoustics[2];
u8 vid;
u8 vrm;
@@ -314,35 +319,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)
{
@@ -550,6 +526,88 @@ 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);
+ long val;
+
+ switch (sattr->index) {
+ case 0:
+ val = data->enh_acoustics[0] & 0xf;
+ break;
+ case 1:
+ val = (data->enh_acoustics[1] >> 4) & 0xf;
+ break;
+ case 2:
+ default:
+ val = data->enh_acoustics[1] & 0xf;
+ break;
+ }
+
+ 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 = 0;
+ idx = 1;
+ break;
+ case 2:
+ default:
+ reg = REG_ENHANCE_ACOUSTICS2;
+ shift = 4;
+ idx = 1;
+ break;
+ }
+
+ if (val > 0) {
+ val = find_closest_descending(val, ad7475_st_map,
+ ARRAY_SIZE(ad7475_st_map));
+ val |= 0x8;
+ }
+
+ mutex_lock(&data->lock);
+
+ data->enh_acoustics[idx] &= ~(0xf << shift);
+ data->enh_acoustics[idx] |= (val << shift);
+
+ i2c_smbus_write_byte_data(client, reg, data->enh_acoustics[idx]);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
/*
* Table of autorange values - the user will write the value in millidegrees,
* and we'll convert it
@@ -606,7 +664,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;
@@ -728,6 +786,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_disable(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_acoustics[0] & mask));
+}
+
+static ssize_t set_stall_disable(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_acoustics[0] &= ~mask;
+ if (val)
+ data->enh_acoustics[0] |= mask;
+
+ i2c_smbus_write_byte_data(client, REG_ENHANCE_ACOUSTICS1,
+ data->enh_acoustics[0]);
mutex_unlock(&data->lock);
@@ -839,7 +934,7 @@ static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr,
/* List of frequencies for the PWM */
static const int pwmfreq_table[] = {
- 11, 14, 22, 29, 35, 44, 58, 88
+ 11, 14, 22, 29, 35, 44, 58, 88, 22500
};
static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
@@ -847,9 +942,10 @@ static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
{
struct adt7475_data *data = adt7475_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int i = clamp_val(data->range[sattr->index] & 0xf, 0,
+ ARRAY_SIZE(pwmfreq_table) - 1);
- return sprintf(buf, "%d\n",
- pwmfreq_table[data->range[sattr->index] & 7]);
+ return sprintf(buf, "%d\n", pwmfreq_table[i]);
}
static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
@@ -864,13 +960,13 @@ 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);
data->range[sattr->index] =
adt7475_read(TEMP_TRANGE_REG(sattr->index));
- data->range[sattr->index] &= ~7;
+ data->range[sattr->index] &= ~0xf;
data->range[sattr->index] |= out;
i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
@@ -995,6 +1091,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,
@@ -1011,6 +1109,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);
@@ -1028,6 +1128,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);
@@ -1056,6 +1158,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_disable, S_IRUGO | S_IWUSR,
+ show_stall_disable, set_stall_disable, 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,
@@ -1068,6 +1172,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_disable, S_IRUGO | S_IWUSR,
+ show_stall_disable, set_stall_disable, 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,
@@ -1080,6 +1186,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_disable, S_IRUGO | S_IWUSR,
+ show_stall_disable, set_stall_disable, 0, 2);
/* Non-standard name, might need revisiting */
static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit);
@@ -1106,6 +1214,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,
@@ -1115,6 +1224,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,
@@ -1125,6 +1235,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,
@@ -1140,12 +1251,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_disable.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_disable.dev_attr.attr,
&dev_attr_pwm_use_point2_pwm_at_crit.attr,
NULL,
};
@@ -1164,6 +1277,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_disable.dev_attr.attr,
NULL
};