271 lines
9.4 KiB
Diff
271 lines
9.4 KiB
Diff
From: Jean Delvare <khali@linux-fr.org>
|
|
Date: Mon, 16 Jan 2012 22:51:48 +0100
|
|
Subject: [PATCH] hwmon: (it87) Add IT8728F support
|
|
|
|
commit 16b5dda22e3798e61bb008d2329d4f4d90ef764e upstream.
|
|
|
|
Until we get a datasheet for the IT8728F, treat it as fully compatible
|
|
with the IT8721F, as it seems to work reasonably well.
|
|
|
|
This closes kernel bug #27262.
|
|
|
|
Signed-off-by: Jean Delvare <khali@linux-fr.org>
|
|
Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
|
|
---
|
|
Documentation/hwmon/it87 | 13 +++++++--
|
|
drivers/hwmon/Kconfig | 4 +-
|
|
drivers/hwmon/it87.c | 61 ++++++++++++++++++++++++++++++++++-----------
|
|
3 files changed, 58 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
|
|
index 6f496a5..23b7def 100644
|
|
--- a/Documentation/hwmon/it87
|
|
+++ b/Documentation/hwmon/it87
|
|
@@ -26,6 +26,10 @@ Supported chips:
|
|
Prefix: 'it8721'
|
|
Addresses scanned: from Super I/O config space (8 I/O ports)
|
|
Datasheet: Not publicly available
|
|
+ * IT8728F
|
|
+ Prefix: 'it8728'
|
|
+ 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)
|
|
@@ -71,7 +75,7 @@ Description
|
|
-----------
|
|
|
|
This driver implements support for the IT8705F, IT8712F, IT8716F,
|
|
-IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips.
|
|
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, 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
|
|
@@ -105,6 +109,9 @@ The IT8726F is just bit enhanced IT8716F with additional hardware
|
|
for AMD power sequencing. Therefore the chip will appear as IT8716F
|
|
to userspace applications.
|
|
|
|
+The IT8728F is considered compatible with the IT8721F, until a datasheet
|
|
+becomes available (hopefully.)
|
|
+
|
|
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
|
when the Overtemperature Shutdown limit is crossed.
|
|
|
|
@@ -121,8 +128,8 @@ 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 (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does
|
|
-not have limit registers.
|
|
+0.016 volt (except IT8721F/IT8758E and IT8728F: 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
|
|
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
|
index f468bbb..0226040 100644
|
|
--- a/drivers/hwmon/Kconfig
|
|
+++ b/drivers/hwmon/Kconfig
|
|
@@ -474,8 +474,8 @@ config SENSORS_IT87
|
|
select HWMON_VID
|
|
help
|
|
If you say yes here you get support for ITE IT8705F, IT8712F,
|
|
- IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
|
|
- chips, and the SiS960 clone.
|
|
+ IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F 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.
|
|
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
|
|
index 603ef2a..0054d6f 100644
|
|
--- a/drivers/hwmon/it87.c
|
|
+++ b/drivers/hwmon/it87.c
|
|
@@ -17,6 +17,7 @@
|
|
* IT8720F Super I/O chip w/LPC interface
|
|
* IT8721F Super I/O chip w/LPC interface
|
|
* IT8726F Super I/O chip w/LPC interface
|
|
+ * IT8728F Super I/O chip w/LPC interface
|
|
* IT8758E Super I/O chip w/LPC interface
|
|
* Sis950 A clone of the IT8705F
|
|
*
|
|
@@ -58,7 +59,7 @@
|
|
|
|
#define DRVNAME "it87"
|
|
|
|
-enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
|
|
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
|
|
|
|
static unsigned short force_id;
|
|
module_param(force_id, ushort, 0);
|
|
@@ -135,6 +136,7 @@ static inline void superio_exit(void)
|
|
#define IT8720F_DEVID 0x8720
|
|
#define IT8721F_DEVID 0x8721
|
|
#define IT8726F_DEVID 0x8726
|
|
+#define IT8728F_DEVID 0x8728
|
|
#define IT87_ACT_REG 0x30
|
|
#define IT87_BASE_REG 0x60
|
|
|
|
@@ -274,11 +276,31 @@ struct it87_data {
|
|
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
|
|
};
|
|
|
|
+static inline int has_12mv_adc(const struct it87_data *data)
|
|
+{
|
|
+ /*
|
|
+ * IT8721F and later have a 12 mV ADC, also with internal scaling
|
|
+ * on selected inputs.
|
|
+ */
|
|
+ return data->type == it8721
|
|
+ || data->type == it8728;
|
|
+}
|
|
+
|
|
+static inline int has_newer_autopwm(const struct it87_data *data)
|
|
+{
|
|
+ /*
|
|
+ * IT8721F and later have separate registers for the temperature
|
|
+ * mapping and the manual duty cycle.
|
|
+ */
|
|
+ return data->type == it8721
|
|
+ || data->type == it8728;
|
|
+}
|
|
+
|
|
static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
|
{
|
|
long lsb;
|
|
|
|
- if (data->type == it8721) {
|
|
+ if (has_12mv_adc(data)) {
|
|
if (data->in_scaled & (1 << nr))
|
|
lsb = 24;
|
|
else
|
|
@@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
|
|
|
static int in_from_reg(const struct it87_data *data, int nr, int val)
|
|
{
|
|
- if (data->type == it8721) {
|
|
+ if (has_12mv_adc(data)) {
|
|
if (data->in_scaled & (1 << nr))
|
|
return val * 24;
|
|
else
|
|
@@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm)
|
|
|
|
static u8 pwm_to_reg(const struct it87_data *data, long val)
|
|
{
|
|
- if (data->type == it8721)
|
|
+ if (has_newer_autopwm(data))
|
|
return val;
|
|
else
|
|
return val >> 1;
|
|
@@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val)
|
|
|
|
static int pwm_from_reg(const struct it87_data *data, u8 reg)
|
|
{
|
|
- if (data->type == it8721)
|
|
+ if (has_newer_autopwm(data))
|
|
return reg;
|
|
else
|
|
return (reg & 0x7f) << 1;
|
|
@@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
|
|
|| data->type == it8716
|
|
|| data->type == it8718
|
|
|| data->type == it8720
|
|
- || data->type == it8721;
|
|
+ || data->type == it8721
|
|
+ || data->type == it8728;
|
|
}
|
|
|
|
static inline int has_old_autopwm(const struct it87_data *data)
|
|
@@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev,
|
|
data->fan_main_ctrl);
|
|
} else {
|
|
if (val == 1) /* Manual mode */
|
|
- data->pwm_ctrl[nr] = data->type == it8721 ?
|
|
+ data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
|
|
data->pwm_temp_map[nr] :
|
|
data->pwm_duty[nr];
|
|
else /* Automatic mode */
|
|
@@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&data->update_lock);
|
|
- if (data->type == it8721) {
|
|
+ if (has_newer_autopwm(data)) {
|
|
/* If we are in automatic mode, the PWM duty cycle register
|
|
* is read-only so we can't write the value */
|
|
if (data->pwm_ctrl[nr] & 0x80) {
|
|
@@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
|
|
struct it87_data *data = dev_get_drvdata(dev);
|
|
int nr = to_sensor_dev_attr(attr)->index;
|
|
|
|
- return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
|
|
- : labels[nr]);
|
|
+ return sprintf(buf, "%s\n", has_12mv_adc(data) ? 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);
|
|
@@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address,
|
|
case IT8721F_DEVID:
|
|
sio_data->type = it8721;
|
|
break;
|
|
+ case IT8728F_DEVID:
|
|
+ sio_data->type = it8728;
|
|
+ break;
|
|
case 0xffff: /* No device at all */
|
|
goto exit;
|
|
default:
|
|
@@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address,
|
|
superio_select(GPIO);
|
|
|
|
reg = superio_inb(IT87_SIO_GPIO3_REG);
|
|
- if (sio_data->type == it8721) {
|
|
- /* The IT8721F/IT8758E doesn't have VID pins at all */
|
|
+ if (sio_data->type == it8721 || sio_data->type == it8728) {
|
|
+ /*
|
|
+ * The IT8721F/IT8758E doesn't have VID pins at all,
|
|
+ * not sure about the IT8728F.
|
|
+ */
|
|
sio_data->skip_vid = 1;
|
|
} else {
|
|
/* We need at least 4 VID pins */
|
|
@@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address,
|
|
}
|
|
if (reg & (1 << 0))
|
|
sio_data->internal |= (1 << 0);
|
|
- if ((reg & (1 << 1)) || sio_data->type == it8721)
|
|
+ if ((reg & (1 << 1)) || sio_data->type == it8721 ||
|
|
+ sio_data->type == it8728)
|
|
sio_data->internal |= (1 << 1);
|
|
|
|
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
|
@@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|
"it8718",
|
|
"it8720",
|
|
"it8721",
|
|
+ "it8728",
|
|
};
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
|
@@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|
enable_pwm_interface = it87_check_pwm(dev);
|
|
|
|
/* Starting with IT8721F, we handle scaling of internal voltages */
|
|
- if (data->type == it8721) {
|
|
+ if (has_12mv_adc(data)) {
|
|
if (sio_data->internal & (1 << 0))
|
|
data->in_scaled |= (1 << 3); /* in3 is AVCC */
|
|
if (sio_data->internal & (1 << 1))
|
|
@@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
|
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
|
|
{
|
|
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
|
|
- if (data->type == it8721) {
|
|
+ if (has_newer_autopwm(data)) {
|
|
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
|
|
data->pwm_duty[nr] = it87_read_value(data,
|
|
IT87_REG_PWM_DUTY(nr));
|
|
--
|
|
1.7.9
|
|
|