All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joshua Scott <joshua.scott@alliedtelesis.co.nz>
To: Jean Delvare <jdelvare@suse.com>,
	Guenter Roeck <linux@roeck-us.net>,
	linux-hwmon@vger.kernel.org
Cc: Joshua Scott <joshua.scott@alliedtelesis.co.nz>,
	Chris Packham <chris.packham@alliedtelesis.co.nz>
Subject: [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs
Date: Mon, 16 May 2016 17:20:32 +1200	[thread overview]
Message-ID: <1463376032-21196-1-git-send-email-joshua.scott@alliedtelesis.co.nz> (raw)

The ADT7470 supports a variety of PWM frequencies. This patch allows the
frequency to be configured and viewed through sysfs.

The valid options are:
 -> 11.0 Hz
 -> 14.7 Hz
 -> 22.1 Hz
 -> 29.4 Hz
 -> 35.3 Hz
 -> 44.1 Hz
 -> 58.8 Hz
 -> 88.2 Hz
 -> 1.4 kHz
 -> 22.5 kHz

Signed-off-by: Joshua Scott <joshua.scott@alliedtelesis.co.nz>
---
 Documentation/hwmon/adt7470 |  17 +++++
 drivers/hwmon/adt7470.c     | 150 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 167 insertions(+)

diff --git a/Documentation/hwmon/adt7470 b/Documentation/hwmon/adt7470
index 8ce4aa0..f8a58f0 100644
--- a/Documentation/hwmon/adt7470
+++ b/Documentation/hwmon/adt7470
@@ -65,6 +65,23 @@ from 0 (off) to 255 (full speed).  Fan speed will be set to maximum when the
 temperature sensor associated with the PWM control exceeds
 pwm#_auto_point2_temp.
 
+The driver also allows control of the PWM frequency:
+
+* pwm_freq
+
+The following frequencies are valid:
+
+* 11.0 Hz
+* 14.7 Hz
+* 22.1 Hz
+* 29.4 Hz
+* 35.3 Hz
+* 44.1 Hz
+* 58.8 Hz
+* 88.2 Hz
+* 1.4 kHz
+* 22.5 kHz
+
 Notes
 -----
 
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index f5da39a..e5f0d6e 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -83,6 +83,7 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
 #define ADT7470_REG_PWM_MIN_MAX_ADDR		0x6D
 #define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR	0x6E
 #define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR	0x71
+#define ADT7470_REG_CFG_2			0x74
 #define ADT7470_REG_ACOUSTICS12			0x75
 #define ADT7470_REG_ACOUSTICS34			0x76
 #define ADT7470_REG_DEVICE			0x3D
@@ -142,6 +143,32 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
 #define FAN_PERIOD_INVALID	65535
 #define FAN_DATA_VALID(x)	((x) && (x) != FAN_PERIOD_INVALID)
 
+/* The datasheet includes a table of available pwm frequencies
+ * controlled by values in config registers 1 and 2.
+ */
+#define ADT7470_CFG_LF		0x40
+#define ADT7470_FREQ_BITS	0x70
+#define ADT7470_CFG_LF_11_0_HZ	0x00
+#define ADT7470_CFG_LF_14_7_HZ	0x10
+#define ADT7470_CFG_LF_22_1_HZ	0x20
+#define ADT7470_CFG_LF_29_4_HZ	0x30
+#define ADT7470_CFG_LF_35_3_HZ	0x40
+#define ADT7470_CFG_LF_44_1_HZ	0x50
+#define ADT7470_CFG_LF_58_8_HZ	0x60
+#define ADT7470_CFG_LF_88_2_HZ	0x70
+#define ADT7470_CFG_HF_1_4_KHZ	0x00
+#define ADT7470_CFG_HF_22_5_KHZ	0x10
+#define ADT7470_11_0_HZ_STR  "11.0 Hz"
+#define ADT7470_14_7_HZ_STR  "14.7 Hz"
+#define ADT7470_22_1_HZ_STR  "22.1 Hz"
+#define ADT7470_29_4_HZ_STR  "29.4 Hz"
+#define ADT7470_35_3_HZ_STR  "35.3 Hz"
+#define ADT7470_44_1_HZ_STR  "44.1 Hz"
+#define ADT7470_58_8_HZ_STR  "58.8 Hz"
+#define ADT7470_88_2_HZ_STR  "88.2 Hz"
+#define ADT7470_1_4_KHZ_STR  "1.4 kHz"
+#define ADT7470_22_5_KHZ_STR "22.5 kHz"
+
 struct adt7470_data {
 	struct i2c_client	*client;
 	struct mutex		lock;
@@ -688,6 +715,126 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
 	return count;
 }
 
+static ssize_t show_pwm_freq(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct adt7470_data *data = adt7470_update_device(dev);
+	unsigned char cfg_reg_1;
+	unsigned char cfg_reg_2;
+	char *freq = "invalid";
+
+	mutex_lock(&data->lock);
+	cfg_reg_1 = i2c_smbus_read_byte_data(data->client, ADT7470_REG_CFG);
+	cfg_reg_2 = i2c_smbus_read_byte_data(data->client, ADT7470_REG_CFG_2);
+	mutex_unlock(&data->lock);
+
+	if (cfg_reg_1 & ADT7470_CFG_LF)
+		switch (cfg_reg_2 & ADT7470_FREQ_BITS) {
+		case ADT7470_CFG_LF_11_0_HZ:
+			freq = ADT7470_11_0_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_14_7_HZ:
+			freq = ADT7470_14_7_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_22_1_HZ:
+			freq = ADT7470_22_1_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_29_4_HZ:
+			freq = ADT7470_29_4_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_35_3_HZ:
+			freq = ADT7470_35_3_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_44_1_HZ:
+			freq = ADT7470_44_1_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_58_8_HZ:
+			freq = ADT7470_58_8_HZ_STR;
+			break;
+		case ADT7470_CFG_LF_88_2_HZ:
+			freq = ADT7470_88_2_HZ_STR;
+			break;
+		}
+	else
+		switch (cfg_reg_2 & ADT7470_FREQ_BITS) {
+		case ADT7470_CFG_HF_1_4_KHZ:
+			freq = ADT7470_1_4_KHZ_STR;
+			break;
+		default:
+			freq = ADT7470_22_5_KHZ_STR;
+			break;
+		}
+	return scnprintf(buf, PAGE_SIZE, "%s\n", freq);
+}
+
+static ssize_t set_pwm_freq(struct device *dev,
+			    struct device_attribute *devattr,
+			    const char *buf, size_t count)
+{
+	struct adt7470_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	int low_freq = ADT7470_CFG_LF;
+	int freq_bits;
+	unsigned char val;
+
+	if (!strncmp(ADT7470_11_0_HZ_STR, buf, strlen(ADT7470_11_0_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_11_0_HZ;
+
+	else if (!strncmp(ADT7470_14_7_HZ_STR, buf,
+			  strlen(ADT7470_14_7_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_14_7_HZ;
+
+	else if (!strncmp(ADT7470_22_1_HZ_STR, buf,
+			  strlen(ADT7470_22_1_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_22_1_HZ;
+
+	else if (!strncmp(ADT7470_29_4_HZ_STR, buf,
+			  strlen(ADT7470_29_4_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_29_4_HZ;
+
+	else if (!strncmp(ADT7470_35_3_HZ_STR, buf,
+			  strlen(ADT7470_35_3_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_35_3_HZ;
+
+	else if (!strncmp(ADT7470_44_1_HZ_STR, buf,
+			  strlen(ADT7470_44_1_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_44_1_HZ;
+
+	else if (!strncmp(ADT7470_58_8_HZ_STR, buf,
+			  strlen(ADT7470_58_8_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_58_8_HZ;
+
+	else if (!strncmp(ADT7470_88_2_HZ_STR, buf,
+			  strlen(ADT7470_88_2_HZ_STR)))
+		freq_bits = ADT7470_CFG_LF_88_2_HZ;
+
+	else if (!strncmp(ADT7470_1_4_KHZ_STR, buf,
+			  strlen(ADT7470_1_4_KHZ_STR))) {
+		freq_bits = ADT7470_CFG_HF_1_4_KHZ;
+		low_freq = 0;
+
+	} else if (!strncmp(ADT7470_22_5_KHZ_STR, buf,
+			  strlen(ADT7470_22_5_KHZ_STR))) {
+		freq_bits = ADT7470_CFG_HF_22_5_KHZ;
+		low_freq = 0;
+
+	} else
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	/* Configuration Register 1 */
+	val = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG,
+				  (val & ~ADT7470_CFG_LF) | low_freq);
+	/* Configuration Register 2 */
+	val = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG_2);
+	i2c_smbus_write_byte_data(client, ADT7470_REG_CFG_2,
+				  (val & ~ADT7470_FREQ_BITS) | freq_bits);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
 static ssize_t show_pwm_max(struct device *dev,
 			    struct device_attribute *devattr,
 			    char *buf)
@@ -1038,6 +1185,8 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
 static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
 static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
 
+static DEVICE_ATTR(pwm_freq, S_IWUSR | S_IRUGO, show_pwm_freq, set_pwm_freq);
+
 static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
 		    show_pwm_min, set_pwm_min, 0);
 static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
@@ -1096,6 +1245,7 @@ static struct attribute *adt7470_attrs[] = {
 	&dev_attr_alarm_mask.attr,
 	&dev_attr_num_temp_sensors.attr,
 	&dev_attr_auto_update_interval.attr,
+	&dev_attr_pwm_freq.attr,
 	&sensor_dev_attr_temp1_max.dev_attr.attr,
 	&sensor_dev_attr_temp2_max.dev_attr.attr,
 	&sensor_dev_attr_temp3_max.dev_attr.attr,
-- 
2.8.1

             reply	other threads:[~2016-05-16  5:20 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-16  5:20 Joshua Scott [this message]
2016-05-18 15:42 ` [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs Guenter Roeck
2016-08-01  5:41 Joshua Scott
2016-08-02 22:44 ` Guenter Roeck
2016-08-08  1:35 Joshua Scott
2016-08-12 13:12 ` Guenter Roeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1463376032-21196-1-git-send-email-joshua.scott@alliedtelesis.co.nz \
    --to=joshua.scott@alliedtelesis.co.nz \
    --cc=chris.packham@alliedtelesis.co.nz \
    --cc=jdelvare@suse.com \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux@roeck-us.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.