diff options
Diffstat (limited to 'drivers/hwmon/it87.c')
-rw-r--r-- | drivers/hwmon/it87.c | 116 |
1 files changed, 94 insertions, 22 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 7a3616ccbf05..14a5d981be7d 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -15,7 +15,9 @@ * IT8716F Super I/O chip w/LPC interface * IT8718F Super I/O chip w/LPC interface * IT8720F Super I/O chip w/LPC interface + * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface + * IT8758E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -54,7 +56,7 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -126,6 +128,7 @@ superio_exit(void) #define IT8716F_DEVID 0x8716 #define IT8718F_DEVID 0x8718 #define IT8720F_DEVID 0x8720 +#define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -229,6 +232,7 @@ struct it87_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ + u16 in_scaled; /* Internal voltage sensors are scaled */ u8 in[9]; /* Register value */ u8 in_max[8]; /* Register value */ u8 in_min[8]; /* Register value */ @@ -260,8 +264,32 @@ struct it87_data { s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ }; -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255)) -#define IN_FROM_REG(val) ((val) * 16) +static u8 in_to_reg(const struct it87_data *data, int nr, long val) +{ + long lsb; + + if (data->type == it8721) { + if (data->in_scaled & (1 << nr)) + lsb = 24; + else + lsb = 12; + } else + lsb = 16; + + val = DIV_ROUND_CLOSEST(val, lsb); + return SENSORS_LIMIT(val, 0, 255); +} + +static int in_from_reg(const struct it87_data *data, int nr, int val) +{ + if (data->type == it8721) { + if (data->in_scaled & (1 << nr)) + return val * 24; + else + return val * 12; + } else + return val * 16; +} static inline u8 FAN_TO_REG(long rpm, int div) { @@ -289,8 +317,22 @@ static inline u16 FAN16_TO_REG(long rpm) ((val) + 500) / 1000), -128, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) -#define PWM_TO_REG(val) ((val) >> 1) -#define PWM_FROM_REG(val) (((val) & 0x7f) << 1) +static u8 pwm_to_reg(const struct it87_data *data, long val) +{ + if (data->type == it8721) + return val; + else + return val >> 1; +} + +static int pwm_from_reg(const struct it87_data *data, u8 reg) +{ + if (data->type == it8721) + return reg; + else + return (reg & 0x7f) << 1; +} + static int DIV_TO_REG(int val) { @@ -321,7 +363,8 @@ static inline int has_16bit_fans(const struct it87_data *data) || (data->type == it8712 && data->revision >= 0x08) || data->type == it8716 || data->type == it8718 - || data->type == it8720; + || data->type == it8720 + || data->type == it8721; } static inline int has_old_autopwm(const struct it87_data *data) @@ -359,7 +402,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr])); } static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, @@ -369,7 +412,7 @@ static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr])); } static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, @@ -379,7 +422,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr])); } static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, @@ -395,7 +438,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); + data->in_min[nr] = in_to_reg(data, nr, val); it87_write_value(data, IT87_REG_VIN_MIN(nr), data->in_min[nr]); mutex_unlock(&data->update_lock); @@ -414,7 +457,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); + data->in_max[nr] = in_to_reg(data, nr, val); it87_write_value(data, IT87_REG_VIN_MAX(nr), data->in_max[nr]); mutex_unlock(&data->update_lock); @@ -644,7 +687,8 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm_duty[nr])); + return sprintf(buf, "%d\n", + pwm_from_reg(data, data->pwm_duty[nr])); } static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, char *buf) @@ -814,7 +858,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->pwm_duty[nr] = PWM_TO_REG(val); + data->pwm_duty[nr] = pwm_to_reg(data, val); /* If we are in manual mode, write the duty cycle immediately; * otherwise, just store it for later use. */ if (!(data->pwm_ctrl[nr] & 0x80)) { @@ -918,7 +962,8 @@ static ssize_t show_auto_pwm(struct device *dev, int nr = sensor_attr->nr; int point = sensor_attr->index; - return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point])); + return sprintf(buf, "%d\n", + pwm_from_reg(data, data->auto_pwm[nr][point])); } static ssize_t set_auto_pwm(struct device *dev, @@ -935,7 +980,7 @@ static ssize_t set_auto_pwm(struct device *dev, return -EINVAL; mutex_lock(&data->update_lock); - data->auto_pwm[nr][point] = PWM_TO_REG(val); + data->auto_pwm[nr][point] = pwm_to_reg(data, val); it87_write_value(data, IT87_REG_AUTO_PWM(nr, point), data->auto_pwm[nr][point]); mutex_unlock(&data->update_lock); @@ -1205,9 +1250,16 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, "5VSB", "Vbat", }; + static const char *labels_it8721[] = { + "+3.3V", + "3VSB", + "Vbat", + }; + struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; - return sprintf(buf, "%s\n", labels[nr]); + return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] + : labels[nr]); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1492,6 +1544,9 @@ static int __init it87_find(unsigned short *address, case IT8720F_DEVID: sio_data->type = it8720; break; + case IT8721F_DEVID: + sio_data->type = it8721; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1532,11 +1587,17 @@ static int __init it87_find(unsigned short *address, int reg; superio_select(GPIO); - /* We need at least 4 VID pins */ + reg = superio_inb(IT87_SIO_GPIO3_REG); - if (reg & 0x0f) { - pr_info("it87: VID is disabled (pins used for GPIO)\n"); + if (sio_data->type == it8721) { + /* The IT8721F/IT8758E doesn't have VID pins at all */ sio_data->skip_vid = 1; + } else { + /* We need at least 4 VID pins */ + if (reg & 0x0f) { + pr_info("it87: VID is disabled (pins used for GPIO)\n"); + sio_data->skip_vid = 1; + } } /* Check if fan3 is there or not */ @@ -1574,7 +1635,7 @@ static int __init it87_find(unsigned short *address, } if (reg & (1 << 0)) sio_data->internal |= (1 << 0); - if (reg & (1 << 1)) + if ((reg & (1 << 1)) || sio_data->type == it8721) sio_data->internal |= (1 << 1); sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; @@ -1652,6 +1713,7 @@ static int __devinit it87_probe(struct platform_device *pdev) "it8716", "it8718", "it8720", + "it8721", }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -1688,6 +1750,16 @@ static int __devinit it87_probe(struct platform_device *pdev) /* Check PWM configuration */ enable_pwm_interface = it87_check_pwm(dev); + /* Starting with IT8721F, we handle scaling of internal voltages */ + if (data->type == it8721) { + if (sio_data->internal & (1 << 0)) + data->in_scaled |= (1 << 3); /* in3 is AVCC */ + if (sio_data->internal & (1 << 1)) + data->in_scaled |= (1 << 7); /* in7 is VSB */ + if (sio_data->internal & (1 << 2)) + data->in_scaled |= (1 << 8); /* in8 is Vbat */ + } + /* Initialize the IT87 chip */ it87_init_device(pdev); @@ -2053,7 +2125,7 @@ static struct it87_data *it87_update_device(struct device *dev) data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); /* The 8705 does not have VID capability. - The 8718 and the 8720 don't use IT87_REG_VID for the + The 8718 and later don't use IT87_REG_VID for the same purpose. */ if (data->type == it8712 || data->type == it8716) { data->vid = it87_read_value(data, IT87_REG_VID); @@ -2153,7 +2225,7 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron, " "Jean Delvare <khali@linux-fr.org>"); -MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver"); +MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); module_param(fix_pwm_polarity, bool, 0); |