Commit 44c1bcd4 authored by Jean Delvare's avatar Jean Delvare Committed by Jean Delvare

hwmon: (it87) Add support for the IT8721F/IT8758E

Add support for the IT8721F/IT8758E. These new chips differ from the
older IT87xxF chips in the following ways:
* ADC LSB is 12 mV instead of 16 mV.
* PWM values are 8-bit instead of 7-bit.
There are other minor changes we don't have to care about in the
driver.

Another change is that we will handle internal voltage scaling in the
driver instead of delegating the work to user-space.
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 0df6454d
......@@ -22,6 +22,10 @@ Supported chips:
Prefix: 'it8720'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* IT8721F/IT8758E
Prefix: 'it8721'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* SiS950 [clone of IT8705F]
Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports)
......@@ -67,7 +71,7 @@ Description
-----------
This driver implements support for the IT8705F, IT8712F, IT8716F,
IT8718F, IT8720F, IT8726F and SiS950 chips.
IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
......@@ -86,14 +90,15 @@ the driver won't notice and report changes in the VID value. The two
upper VID bits share their pins with voltage inputs (in5 and in6) so you
can't have both on a given board.
The IT8716F, IT8718F, IT8720F and later IT8712F revisions have support for
2 additional fans. The additional fans are supported by the driver.
The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions
have support for 2 additional fans. The additional fans are supported by the
driver.
The IT8716F, IT8718F and IT8720F, and late IT8712F and IT8705F also have
optional 16-bit tachometer counters for fans 1 to 3. This is better (no more
fan clock divider mess) but not compatible with the older chips and
revisions. The 16-bit tachometer mode is enabled by the driver when one
of the above chips is detected.
The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and
IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This
is better (no more fan clock divider mess) but not compatible with the older
chips and revisions. The 16-bit tachometer mode is enabled by the driver when
one of the above chips is detected.
The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F
......@@ -115,7 +120,12 @@ alarm is triggered if the voltage has crossed a programmable minimum or
maximum limit. Note that minimum in this case always means 'closest to
zero'; this is important for negative voltage measurements. All voltage
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
0.016 volt. The battery voltage in8 does not have limit registers.
0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does
not have limit registers.
On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
the chip (in7, in8 and optionally in3). The driver handles this transparently
so user-space doesn't have to care.
The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
the voltage level your processor should work with. This is hardcoded by
......
......@@ -428,8 +428,8 @@ config SENSORS_IT87
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
IT8716F, IT8718F, IT8720F and IT8726F sensor chips, and the
SiS960 clone.
IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
......
......@@ -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,12 +1587,18 @@ 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 (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 */
if (reg & (1 << 6))
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment