Prechádzať zdrojové kódy

hwmon: (lm85) Add support for ADT7468 high-frequency PWM mode

The ADT7468 supports a high-frequency PWM output mode where all PWM
outputs are driven by a 22.5 kHz clock. Add support for this mode, and
document it, as it may surprise the user that setting one PWM output
frequency also affects the other PWM outputs.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Darrick J. Wong <djwong@us.ibm.com>
Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Jean Delvare 14 rokov pred
rodič
commit
f6c61cff8b
2 zmenil súbory, kde vykonal 35 pridanie a 7 odobranie
  1. 7 0
      Documentation/hwmon/lm85
  2. 28 7
      drivers/hwmon/lm85.c

+ 7 - 0
Documentation/hwmon/lm85

@@ -101,6 +101,13 @@ Devices has confirmed this "bug". The ADT7463 is reported to work as
 described in the documentation. The current lm85 driver does not show the
 described in the documentation. The current lm85 driver does not show the
 offset register.
 offset register.
 
 
+The ADT7468 has a high-frequency PWM mode, where all PWM outputs are
+driven by a 22.5 kHz clock. This is a global mode, not per-PWM output,
+which means that setting any PWM frequency above 11.3 kHz will switch
+all 3 PWM outputs to a 22.5 kHz frequency. Conversely, setting any PWM
+frequency below 11.3 kHz will switch all 3 PWM outputs to a frequency
+between 10 and 100 Hz, which can then be tuned separately.
+
 See the vendor datasheets for more information. There is application note
 See the vendor datasheets for more information. There is application note
 from National (AN-1260) with some additional information about the LM85.
 from National (AN-1260) with some additional information about the LM85.
 The Analog Devices datasheet is very detailed and describes a procedure for
 The Analog Devices datasheet is very detailed and describes a procedure for

+ 28 - 7
drivers/hwmon/lm85.c

@@ -64,9 +64,12 @@ enum chips {
 #define	LM85_REG_VERSTEP		0x3f
 #define	LM85_REG_VERSTEP		0x3f
 
 
 #define	ADT7468_REG_CFG5		0x7c
 #define	ADT7468_REG_CFG5		0x7c
-#define		ADT7468_OFF64		0x01
+#define		ADT7468_OFF64		(1 << 0)
+#define		ADT7468_HFPWM		(1 << 1)
 #define	IS_ADT7468_OFF64(data)		\
 #define	IS_ADT7468_OFF64(data)		\
 	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
 	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
+#define	IS_ADT7468_HFPWM(data)		\
+	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_HFPWM))
 
 
 /* These are the recognized values for the above regs */
 /* These are the recognized values for the above regs */
 #define	LM85_COMPANY_NATIONAL		0x01
 #define	LM85_COMPANY_NATIONAL		0x01
@@ -567,8 +570,14 @@ static ssize_t show_pwm_freq(struct device *dev,
 {
 {
 	int nr = to_sensor_dev_attr(attr)->index;
 	int nr = to_sensor_dev_attr(attr)->index;
 	struct lm85_data *data = lm85_update_device(dev);
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf, "%d\n", FREQ_FROM_REG(data->freq_map,
-						  data->pwm_freq[nr]));
+	int freq;
+
+	if (IS_ADT7468_HFPWM(data))
+		freq = 22500;
+	else
+		freq = FREQ_FROM_REG(data->freq_map, data->pwm_freq[nr]);
+
+	return sprintf(buf, "%d\n", freq);
 }
 }
 
 
 static ssize_t set_pwm_freq(struct device *dev,
 static ssize_t set_pwm_freq(struct device *dev,
@@ -580,10 +589,22 @@ static ssize_t set_pwm_freq(struct device *dev,
 	long val = simple_strtol(buf, NULL, 10);
 	long val = simple_strtol(buf, NULL, 10);
 
 
 	mutex_lock(&data->update_lock);
 	mutex_lock(&data->update_lock);
-	data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
-	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
-		(data->zone[nr].range << 4)
-		| data->pwm_freq[nr]);
+	/* The ADT7468 has a special high-frequency PWM output mode,
+	 * where all PWM outputs are driven by a 22.5 kHz clock.
+	 * This might confuse the user, but there's not much we can do. */
+	if (data->type == adt7468 && val >= 11300) {	/* High freq. mode */
+		data->cfg5 &= ~ADT7468_HFPWM;
+		lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+	} else {					/* Low freq. mode */
+		data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
+		lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+				 (data->zone[nr].range << 4)
+				 | data->pwm_freq[nr]);
+		if (data->type == adt7468) {
+			data->cfg5 |= ADT7468_HFPWM;
+			lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+		}
+	}
 	mutex_unlock(&data->update_lock);
 	mutex_unlock(&data->update_lock);
 	return count;
 	return count;
 }
 }