hwmon: (it87) Add IT8728F support
authorJean Delvare <khali@linux-fr.org>
Mon, 16 Jan 2012 21:51:48 +0000 (22:51 +0100)
committerJean Delvare <khali@endymion.delvare>
Mon, 16 Jan 2012 21:51:48 +0000 (22:51 +0100)
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
drivers/hwmon/Kconfig
drivers/hwmon/it87.c

index 6f496a5867324cc5750f90ecd0fd91d3547b554d..23b7def21ba8bc5fe9e797e2b4cce1b94245d969 100644 (file)
@@ -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
index f468bbb6357a7a87f9ca9c8b1221fddd83e696cb..02260406b9e440ac406ac3ae7fc3cded1f05bb4e 100644 (file)
@@ -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.
index 603ef2af270758fb4fd9a6f860a779de40c4288f..0054d6f9cec95e4645608c7fec6fde4f646344ac 100644 (file)
@@ -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));