Bladeren bron

hwmon: (it87) Add IT8728F support

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>
Jean Delvare 13 jaren geleden
bovenliggende
commit
16b5dda22e
3 gewijzigde bestanden met toevoegingen van 58 en 20 verwijderingen
  1. 10 3
      Documentation/hwmon/it87
  2. 2 2
      drivers/hwmon/Kconfig
  3. 46 15
      drivers/hwmon/it87.c

+ 10 - 3
Documentation/hwmon/it87

@@ -26,6 +26,10 @@ Supported chips:
     Prefix: 'it8721'
     Prefix: 'it8721'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
     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]
   * SiS950   [clone of IT8705F]
     Prefix: 'it87'
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     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,
 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,
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
 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
 for AMD power sequencing. Therefore the chip will appear as IT8716F
 to userspace applications.
 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
 Temperatures are measured in degrees Celsius. An alarm is triggered once
 when the Overtemperature Shutdown limit is crossed.
 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
 maximum limit. Note that minimum in this case always means 'closest to
 zero'; this is important for negative voltage measurements. All voltage
 zero'; this is important for negative voltage measurements. All voltage
 inputs can measure voltages between 0 and 4.08 volts, with a resolution of
 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
 On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
 the chip (in7, in8 and optionally in3). The driver handles this transparently
 the chip (in7, in8 and optionally in3). The driver handles this transparently

+ 2 - 2
drivers/hwmon/Kconfig

@@ -474,8 +474,8 @@ config SENSORS_IT87
 	select HWMON_VID
 	select HWMON_VID
 	help
 	help
 	  If you say yes here you get support for ITE IT8705F, IT8712F,
 	  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
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
 	  will be called it87.

+ 46 - 15
drivers/hwmon/it87.c

@@ -17,6 +17,7 @@
  *            IT8720F  Super I/O chip w/LPC interface
  *            IT8720F  Super I/O chip w/LPC interface
  *            IT8721F  Super I/O chip w/LPC interface
  *            IT8721F  Super I/O chip w/LPC interface
  *            IT8726F  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
  *            IT8758E  Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
  *            Sis950   A clone of the IT8705F
  *
  *
@@ -58,7 +59,7 @@
 
 
 #define DRVNAME "it87"
 #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;
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
 module_param(force_id, ushort, 0);
@@ -135,6 +136,7 @@ static inline void superio_exit(void)
 #define IT8720F_DEVID 0x8720
 #define IT8720F_DEVID 0x8720
 #define IT8721F_DEVID 0x8721
 #define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT8726F_DEVID 0x8726
+#define IT8728F_DEVID 0x8728
 #define IT87_ACT_REG  0x30
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 #define IT87_BASE_REG 0x60
 
 
@@ -274,11 +276,31 @@ struct it87_data {
 	s8 auto_temp[3][5];	/* [nr][0] is point1_temp_hyst */
 	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)
 static u8 in_to_reg(const struct it87_data *data, int nr, long val)
 {
 {
 	long lsb;
 	long lsb;
 
 
-	if (data->type == it8721) {
+	if (has_12mv_adc(data)) {
 		if (data->in_scaled & (1 << nr))
 		if (data->in_scaled & (1 << nr))
 			lsb = 24;
 			lsb = 24;
 		else
 		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)
 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))
 		if (data->in_scaled & (1 << nr))
 			return val * 24;
 			return val * 24;
 		else
 		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)
 static u8 pwm_to_reg(const struct it87_data *data, long val)
 {
 {
-	if (data->type == it8721)
+	if (has_newer_autopwm(data))
 		return val;
 		return val;
 	else
 	else
 		return val >> 1;
 		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)
 static int pwm_from_reg(const struct it87_data *data, u8 reg)
 {
 {
-	if (data->type == it8721)
+	if (has_newer_autopwm(data))
 		return reg;
 		return reg;
 	else
 	else
 		return (reg & 0x7f) << 1;
 		return (reg & 0x7f) << 1;
@@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
 	    || data->type == it8716
 	    || data->type == it8716
 	    || data->type == it8718
 	    || data->type == it8718
 	    || data->type == it8720
 	    || data->type == it8720
-	    || data->type == it8721;
+	    || data->type == it8721
+	    || data->type == it8728;
 }
 }
 
 
 static inline int has_old_autopwm(const struct it87_data *data)
 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);
 				 data->fan_main_ctrl);
 	} else {
 	} else {
 		if (val == 1)				/* Manual mode */
 		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_temp_map[nr] :
 					     data->pwm_duty[nr];
 					     data->pwm_duty[nr];
 		else					/* Automatic mode */
 		else					/* Automatic mode */
@@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	mutex_lock(&data->update_lock);
 	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
 		/* If we are in automatic mode, the PWM duty cycle register
 		 * is read-only so we can't write the value */
 		 * is read-only so we can't write the value */
 		if (data->pwm_ctrl[nr] & 0x80) {
 		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);
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = to_sensor_dev_attr(attr)->index;
 	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(in3_label, S_IRUGO, show_label, NULL, 0);
 static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
 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:
 	case IT8721F_DEVID:
 		sio_data->type = it8721;
 		sio_data->type = it8721;
 		break;
 		break;
+	case IT8728F_DEVID:
+		sio_data->type = it8728;
+		break;
 	case 0xffff:	/* No device at all */
 	case 0xffff:	/* No device at all */
 		goto exit;
 		goto exit;
 	default:
 	default:
@@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address,
 		superio_select(GPIO);
 		superio_select(GPIO);
 
 
 		reg = superio_inb(IT87_SIO_GPIO3_REG);
 		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;
 			sio_data->skip_vid = 1;
 		} else {
 		} else {
 			/* We need at least 4 VID pins */
 			/* We need at least 4 VID pins */
@@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address,
 		}
 		}
 		if (reg & (1 << 0))
 		if (reg & (1 << 0))
 			sio_data->internal |= (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->internal |= (1 << 1);
 
 
 		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
 		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",
 		"it8718",
 		"it8720",
 		"it8720",
 		"it8721",
 		"it8721",
+		"it8728",
 	};
 	};
 
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 	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);
 	enable_pwm_interface = it87_check_pwm(dev);
 
 
 	/* Starting with IT8721F, we handle scaling of internal voltages */
 	/* Starting with IT8721F, we handle scaling of internal voltages */
-	if (data->type == it8721) {
+	if (has_12mv_adc(data)) {
 		if (sio_data->internal & (1 << 0))
 		if (sio_data->internal & (1 << 0))
 			data->in_scaled |= (1 << 3);	/* in3 is AVCC */
 			data->in_scaled |= (1 << 3);	/* in3 is AVCC */
 		if (sio_data->internal & (1 << 1))
 		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)
 static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
 {
 {
 	data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(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_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
 		data->pwm_duty[nr] = it87_read_value(data,
 		data->pwm_duty[nr] = it87_read_value(data,
 						     IT87_REG_PWM_DUTY(nr));
 						     IT87_REG_PWM_DUTY(nr));