]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/hwmon/adt7470.c
adt7470: fix pwm at a certain level during temperature sensor scan
[karo-tx-linux.git] / drivers / hwmon / adt7470.c
index d368d8f845e1148d83a55da797d11a5758067b0b..b7a442a80bded32d865c467b19fdd827e429fb3f 100644 (file)
@@ -74,6 +74,7 @@ I2C_CLIENT_INSMOD_1(adt7470);
 #define ADT7470_REG_PWM12_CFG                  0x68
 #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_PWM3_AUTO_MASK          0x40
 #define                ADT7470_PWM4_AUTO_MASK          0x80
@@ -223,7 +224,7 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
        unsigned long local_jiffies = jiffies;
-       u8 cfg;
+       u8 cfg, pwm[4], pwm_cfg[2];
        int i;
 
        mutex_lock(&data->lock);
@@ -232,6 +233,24 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
                && data->sensors_valid)
                goto no_sensor_update;
 
+       /* save pwm[1-4] config register */
+       pwm_cfg[0] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(0));
+       pwm_cfg[1] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(2));
+
+       /* set manual pwm to whatever it is set to now */
+       for (i = 0; i < ADT7470_FAN_COUNT; i++)
+               pwm[i] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM(i));
+
+       /* put pwm in manual mode */
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0),
+               pwm_cfg[0] & ~(ADT7470_PWM_AUTO_MASK));
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2),
+               pwm_cfg[1] & ~(ADT7470_PWM_AUTO_MASK));
+
+       /* write pwm control to whatever it was */
+       for (i = 0; i < ADT7470_FAN_COUNT; i++)
+               i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(i), pwm[i]);
+
        /* start reading temperature sensors */
        cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
        cfg |= 0x80;
@@ -249,6 +268,10 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
        cfg &= ~0x80;
        i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
 
+       /* restore pwm[1-4] config registers */
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
+       i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+
        for (i = 0; i < ADT7470_TEMP_COUNT; i++)
                data->temp[i] = i2c_smbus_read_byte_data(client,
                                                ADT7470_TEMP_REG(i));
@@ -353,7 +376,13 @@ static ssize_t set_temp_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = DIV_ROUND_CLOSEST(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_min[attr->index] = temp;
@@ -381,7 +410,13 @@ static ssize_t set_temp_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = DIV_ROUND_CLOSEST(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->temp_max[attr->index] = temp;
@@ -430,11 +465,13 @@ static ssize_t set_fan_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
 
-       if (!temp)
+       if (strict_strtol(buf, 10, &temp) || !temp)
                return -EINVAL;
+
        temp = FAN_RPM_TO_PERIOD(temp);
+       temp = SENSORS_LIMIT(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_max[attr->index] = temp;
@@ -465,11 +502,13 @@ static ssize_t set_fan_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
 
-       if (!temp)
+       if (strict_strtol(buf, 10, &temp) || !temp)
                return -EINVAL;
+
        temp = FAN_RPM_TO_PERIOD(temp);
+       temp = SENSORS_LIMIT(temp, 1, 65534);
 
        mutex_lock(&data->lock);
        data->fan_min[attr->index] = temp;
@@ -507,9 +546,12 @@ static ssize_t set_force_pwm_max(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
        mutex_lock(&data->lock);
        data->force_pwm_max = temp;
        reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
@@ -537,7 +579,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm[attr->index] = temp;
@@ -564,7 +611,12 @@ static ssize_t set_pwm_max(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_max[attr->index] = temp;
@@ -592,7 +644,12 @@ static ssize_t set_pwm_min(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_min[attr->index] = temp;
@@ -630,7 +687,13 @@ static ssize_t set_pwm_tmin(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10) / 1000;
+       long temp;
+
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = DIV_ROUND_CLOSEST(temp, 1000);
+       temp = SENSORS_LIMIT(temp, 0, 255);
 
        mutex_lock(&data->lock);
        data->pwm_tmin[attr->index] = temp;
@@ -658,11 +721,14 @@ static ssize_t set_pwm_auto(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = simple_strtol(buf, NULL, 10);
        int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
        int pwm_auto_reg_mask;
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
        if (attr->index % 2)
                pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
        else
@@ -716,10 +782,14 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct adt7470_data *data = i2c_get_clientdata(client);
-       int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
        int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+       long temp;
        u8 reg;
 
+       if (strict_strtol(buf, 10, &temp))
+               return -EINVAL;
+
+       temp = cvt_auto_temp(temp);
        if (temp < 0)
                return temp;