Signed-off-by: Robert Hancock <robert.hancock@xxxxxxxxxx>
---
Documentation/hwmon/adt7470.rst | 5 ++-
drivers/hwmon/adt7470.c | 72 ++++++++++++++++++++++++++++++++-
2 files changed, 75 insertions(+), 2 deletions(-)
diff --git a/Documentation/hwmon/adt7470.rst b/Documentation/hwmon/adt7470.rst
index d225f816e992..8293f93d6cd5 100644
--- a/Documentation/hwmon/adt7470.rst
+++ b/Documentation/hwmon/adt7470.rst
@@ -69,7 +69,10 @@ from 0 (off) to 255 (full speed). Fan speed will be set to maximum when the
temperature sensor associated with the PWM control exceeds
pwm#_auto_point2_temp.
-The driver also allows control of the PWM frequency:
+The driver also allows control of the PWM inversion and frequency:
+
+* pwm#_invert: Controls whether the PWM output signal is inverted
+ (i.e. low when active rather than high).
* pwm1_freq
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 2e8feacccf84..f0863a6e1560 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -61,10 +61,14 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67
#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68
#define ADT7470_REG_PWM12_CFG 0x68
+#define ADT7470_PWM2_INVERT_MASK 0x10
+#define ADT7470_PWM1_INVERT_MASK 0x20
#define ADT7470_PWM2_AUTO_MASK 0x40
#define ADT7470_PWM1_AUTO_MASK 0x80
#define ADT7470_PWM_AUTO_MASK 0xC0
#define ADT7470_REG_PWM34_CFG 0x69
+#define ADT7470_PWM4_INVERT_MASK 0x10
+#define ADT7470_PWM3_INVERT_MASK 0x20
#define ADT7470_PWM3_AUTO_MASK 0x40
#define ADT7470_PWM4_AUTO_MASK 0x80
#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A
@@ -162,6 +166,7 @@ struct adt7470_data {
u8 pwm_min[ADT7470_PWM_COUNT];
s8 pwm_tmin[ADT7470_PWM_COUNT];
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
+ u8 pwm_invert[ADT7470_PWM_COUNT];
struct task_struct *auto_update;
unsigned int auto_update_interval;
@@ -300,11 +305,22 @@ static int adt7470_update_sensors(struct adt7470_data *data)
reg_mask = ADT7470_PWM1_AUTO_MASK;
reg = ADT7470_REG_PWM_CFG(i);
- if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
+ cfg = i2c_smbus_read_byte_data(client, reg);
+ if (cfg & reg_mask)
data->pwm_automatic[i] = 1;
else
data->pwm_automatic[i] = 0;
+ if (i % 2)
+ reg_mask = ADT7470_PWM2_INVERT_MASK;
+ else
+ reg_mask = ADT7470_PWM1_INVERT_MASK;
+
+ if (cfg & reg_mask)
+ data->pwm_invert[i] = 1;
+ else
+ data->pwm_invert[i] = 0;
+
reg = ADT7470_REG_PWM_AUTO_TEMP(i);
cfg = i2c_smbus_read_byte_data(client, reg);
if (!(i % 2))
@@ -935,6 +951,51 @@ static ssize_t pwm_tmin_store(struct device *dev,
return count;
}
+static ssize_t pwm_invert_show(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ return sprintf(buf, "%d\n", (int)data->pwm_invert[attr->index]);
+}
+
+static ssize_t pwm_invert_store(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int pwm_invert_reg = ADT7470_REG_PWM_CFG(attr->index);
+ int pwm_invert_reg_mask;
+ long temp;
+ u8 reg;
+
+ if (kstrtol(buf, 10, &temp))
+ return -EINVAL;
+
+ if (attr->index % 2)
+ pwm_invert_reg_mask = ADT7470_PWM2_INVERT_MASK;
+ else
+ pwm_invert_reg_mask = ADT7470_PWM1_INVERT_MASK;
+
+ if (temp != 1 && temp != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ data->pwm_invert[attr->index] = temp;
+ reg = i2c_smbus_read_byte_data(client, pwm_invert_reg);
+ if (temp)
+ reg |= pwm_invert_reg_mask;
+ else
+ reg &= ~pwm_invert_reg_mask;
+ i2c_smbus_write_byte_data(client, pwm_invert_reg, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
static ssize_t pwm_auto_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -1135,6 +1196,11 @@ static SENSOR_DEVICE_ATTR_RW(pwm4, pwm, 3);
static DEVICE_ATTR_RW(pwm1_freq);
+static SENSOR_DEVICE_ATTR_RW(pwm1_invert, pwm_invert, 0);
+static SENSOR_DEVICE_ATTR_RW(pwm2_invert, pwm_invert, 1);
+static SENSOR_DEVICE_ATTR_RW(pwm3_invert, pwm_invert, 2);
+static SENSOR_DEVICE_ATTR_RW(pwm4_invert, pwm_invert, 3);
+
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_pwm, pwm_min, 0);
static SENSOR_DEVICE_ATTR_RW(pwm2_auto_point1_pwm, pwm_min, 1);
static SENSOR_DEVICE_ATTR_RW(pwm3_auto_point1_pwm, pwm_min, 2);
@@ -1231,6 +1297,10 @@ static struct attribute *adt7470_attrs[] = {
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm1_invert.dev_attr.attr,
+ &sensor_dev_attr_pwm2_invert.dev_attr.attr,
+ &sensor_dev_attr_pwm3_invert.dev_attr.attr,
+ &sensor_dev_attr_pwm4_invert.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,