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: Jean Delvare <khali@linux-fr.org>
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 7a3616c..14a5d98 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 @@
 #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 @@
 	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 @@
 	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 @@
 					((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 @@
 	    || (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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 		"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 @@
 	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 @@
 		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 @@
 		}
 		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 @@
 		"it8716",
 		"it8718",
 		"it8720",
+		"it8721",
 	};
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1688,6 +1750,16 @@
 	/* 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 @@
 
 		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 @@
 
 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);