diff options
Diffstat (limited to 'drivers/hwmon/lm63.c')
-rw-r--r-- | drivers/hwmon/lm63.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 313aee18be1d..3d882c93b46d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -47,6 +47,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/types.h> /* * Addresses to scan @@ -91,6 +92,8 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; #define LM63_REG_MAN_ID 0xFE #define LM63_REG_CHIP_ID 0xFF +#define LM96163_REG_CONFIG_ENHANCED 0x45 + /* * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. @@ -134,7 +137,7 @@ static struct lm63_data *lm63_update_device(struct device *dev); static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); static void lm63_init_client(struct i2c_client *client); -enum chips { lm63, lm64 }; +enum chips { lm63, lm64, lm96163 }; /* * Driver data (common to all clients) @@ -143,6 +146,7 @@ enum chips { lm63, lm64 }; static const struct i2c_device_id lm63_id[] = { { "lm63", lm63 }, { "lm64", lm64 }, + { "lm96163", lm96163 }, { } }; MODULE_DEVICE_TABLE(i2c, lm63_id); @@ -186,6 +190,7 @@ struct lm63_data { 3: remote offset */ u8 temp2_crit_hyst; u8 alarms; + bool pwm_highres; }; /* @@ -226,9 +231,16 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? + int pwm; + + if (data->pwm_highres) + pwm = data->pwm1_value; + else + pwm = data->pwm1_value >= 2 * data->pwm1_freq ? 255 : (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq)); + (2 * data->pwm1_freq); + + return sprintf(buf, "%d\n", pwm); } static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, @@ -246,9 +258,9 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, if (err) return err; + val = SENSORS_LIMIT(val, 0, 255); mutex_lock(&data->update_lock); - data->pwm1_value = val <= 0 ? 0 : - val >= 255 ? 2 * data->pwm1_freq : + data->pwm1_value = data->pwm_highres ? val : (val * data->pwm1_freq * 2 + 127) / 255; i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); mutex_unlock(&data->update_lock); @@ -522,6 +534,8 @@ static int lm63_detect(struct i2c_client *new_client, strlcpy(info->type, "lm63", I2C_NAME_SIZE); else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) strlcpy(info->type, "lm64", I2C_NAME_SIZE); + else if (chip_id == 0x49 && address == 0x4c) + strlcpy(info->type, "lm96163", I2C_NAME_SIZE); else return -ENODEV; @@ -605,6 +619,23 @@ static void lm63_init_client(struct i2c_client *client) if (data->pwm1_freq == 0) data->pwm1_freq = 1; + /* + * For LM96163, check if high resolution PWM is enabled. + * Also, check if unsigned temperature format is enabled + * and display a warning message if it is. + */ + if (data->kind == lm96163) { + u8 config_enhanced + = i2c_smbus_read_byte_data(client, + LM96163_REG_CONFIG_ENHANCED); + if ((config_enhanced & 0x10) + && !(data->config_fan & 0x08) && data->pwm1_freq == 8) + data->pwm_highres = true; + if (config_enhanced & 0x08) + dev_warn(&client->dev, + "Unsigned format for High and Crit setpoints enabled but not supported by driver\n"); + } + /* Show some debug info about the LM63 configuration */ dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", (data->config & 0x04) ? "tachometer input" : |