linux-hwmon.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs
@ 2016-08-01  5:41 Joshua Scott
  2016-08-02 22:44 ` Guenter Roeck
  0 siblings, 1 reply; 6+ messages in thread
From: Joshua Scott @ 2016-08-01  5:41 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, linux-hwmon; +Cc: Joshua Scott, Chris Packham

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

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

diff --git a/Documentation/hwmon/adt7470 b/Documentation/hwmon/adt7470
index 8ce4aa0..fe68e18 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:
+
+* pwm1_freq
+
+The PWM frequency is rounded to the nearest one of:
+
+* 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..f57026f 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -32,6 +32,7 @@
 #include <linux/log2.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/util_macros.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
@@ -83,6 +84,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 +144,22 @@ 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
+
 struct adt7470_data {
 	struct i2c_client	*client;
 	struct mutex		lock;
@@ -688,6 +706,134 @@ 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;
+	int freq = -EINVAL;
+
+	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 = 11;
+			break;
+		case ADT7470_CFG_LF_14_7_HZ:
+			freq = 15;
+			break;
+		case ADT7470_CFG_LF_22_1_HZ:
+			freq = 22;
+			break;
+		case ADT7470_CFG_LF_29_4_HZ:
+			freq = 29;
+			break;
+		case ADT7470_CFG_LF_35_3_HZ:
+			freq = 35;
+			break;
+		case ADT7470_CFG_LF_44_1_HZ:
+			freq = 44;
+			break;
+		case ADT7470_CFG_LF_58_8_HZ:
+			freq = 59;
+			break;
+		case ADT7470_CFG_LF_88_2_HZ:
+			freq = 88;
+			break;
+		}
+	else
+		switch (cfg_reg_2 & ADT7470_FREQ_BITS) {
+		case ADT7470_CFG_HF_1_4_KHZ:
+			freq = 1400;
+			break;
+		default:
+			freq = 22500;
+			break;
+		}
+	return scnprintf(buf, PAGE_SIZE, "%d\n", freq);
+}
+
+/* These are the valid PWM frequencies to the nearest Hz */
+static const int adt7470_freq_map[] = {
+	11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
+};
+
+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;
+	long freq;
+	int freq_index;
+	int low_freq = ADT7470_CFG_LF;
+	int freq_bits;
+	unsigned char val;
+
+	if (kstrtol(buf, 10, &freq))
+		return -EINVAL;
+
+	/* Round the user value given to the closest available frequency */
+	freq_index = find_closest(freq, adt7470_freq_map,
+				  ARRAY_SIZE(adt7470_freq_map));
+	freq = adt7470_freq_map[freq_index];
+
+	switch (freq) {
+	case 11:
+		freq_bits = ADT7470_CFG_LF_11_0_HZ;
+		break;
+	case 15:
+		freq_bits = ADT7470_CFG_LF_14_7_HZ;
+		break;
+	case 22:
+		freq_bits = ADT7470_CFG_LF_22_1_HZ;
+		break;
+	case 29:
+		freq_bits = ADT7470_CFG_LF_29_4_HZ;
+		break;
+	case 35:
+		freq_bits = ADT7470_CFG_LF_35_3_HZ;
+		break;
+	case 44:
+		freq_bits = ADT7470_CFG_LF_44_1_HZ;
+		break;
+	case 59:
+		freq_bits = ADT7470_CFG_LF_58_8_HZ;
+		break;
+	case 88:
+		freq_bits = ADT7470_CFG_LF_88_2_HZ;
+		break;
+	case 1400:
+		freq_bits = ADT7470_CFG_HF_1_4_KHZ;
+		low_freq = 0;
+		break;
+	case 22500:
+		freq_bits = ADT7470_CFG_HF_22_5_KHZ;
+		low_freq = 0;
+		break;
+	default:
+		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 +1184,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(pwm1_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 +1244,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_pwm1_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.9.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread
* [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs
@ 2016-08-08  1:35 Joshua Scott
  2016-08-12 13:12 ` Guenter Roeck
  0 siblings, 1 reply; 6+ messages in thread
From: Joshua Scott @ 2016-08-08  1:35 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, linux-hwmon; +Cc: Joshua Scott, Chris Packham

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

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

diff --git a/Documentation/hwmon/adt7470 b/Documentation/hwmon/adt7470
index 8ce4aa0..fe68e18 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:
+
+* pwm1_freq
+
+The PWM frequency is rounded to the nearest one of:
+
+* 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..94550d7 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -32,6 +32,7 @@
 #include <linux/log2.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/util_macros.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
@@ -83,6 +84,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 +144,11 @@ 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)
 
+/* Config registers 1 and 2 include fields for selecting the PWM frequency */
+#define ADT7470_CFG_LF		0x40
+#define ADT7470_FREQ_MASK	0x70
+#define ADT7470_FREQ_SHIFT	4
+
 struct adt7470_data {
 	struct i2c_client	*client;
 	struct mutex		lock;
@@ -688,6 +695,70 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
 	return count;
 }
 
+/* These are the valid PWM frequencies to the nearest Hz */
+static const int adt7470_freq_map[] = {
+	11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
+};
+
+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;
+	int index;
+
+	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);
+
+	index = (cfg_reg_2 & ADT7470_FREQ_MASK) >> ADT7470_FREQ_SHIFT;
+	if (!(cfg_reg_1 & ADT7470_CFG_LF))
+		index += 8;
+	if (index >= ARRAY_SIZE(adt7470_freq_map))
+		index = ARRAY_SIZE(adt7470_freq_map) - 1;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", adt7470_freq_map[index]);
+}
+
+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;
+	long freq;
+	int index;
+	int low_freq = ADT7470_CFG_LF;
+	unsigned char val;
+
+	if (kstrtol(buf, 10, &freq))
+		return -EINVAL;
+
+	/* Round the user value given to the closest available frequency */
+	index = find_closest(freq, adt7470_freq_map,
+			     ARRAY_SIZE(adt7470_freq_map));
+
+	if (index >= 8) {
+		index -= 8;
+		low_freq = 0;
+	}
+
+	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_MASK) | (index << ADT7470_FREQ_SHIFT));
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
 static ssize_t show_pwm_max(struct device *dev,
 			    struct device_attribute *devattr,
 			    char *buf)
@@ -1038,6 +1109,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(pwm1_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,
@@ -1154,6 +1227,7 @@ static struct attribute *adt7470_attrs[] = {
 	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
 	&sensor_dev_attr_force_pwm_max.dev_attr.attr,
 	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&dev_attr_pwm1_freq.attr,
 	&sensor_dev_attr_pwm2.dev_attr.attr,
 	&sensor_dev_attr_pwm3.dev_attr.attr,
 	&sensor_dev_attr_pwm4.dev_attr.attr,
-- 
2.9.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread
* [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs
@ 2016-05-16  5:20 Joshua Scott
  2016-05-18 15:42 ` Guenter Roeck
  0 siblings, 1 reply; 6+ messages in thread
From: Joshua Scott @ 2016-05-16  5:20 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck, linux-hwmon; +Cc: Joshua Scott, Chris Packham

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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-08-12 13:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-01  5:41 [PATCH] hwmon: adt7470: Expose PWM frequency to sysfs Joshua Scott
2016-08-02 22:44 ` Guenter Roeck
  -- strict thread matches above, loose matches on Subject: below --
2016-08-08  1:35 Joshua Scott
2016-08-12 13:12 ` Guenter Roeck
2016-05-16  5:20 Joshua Scott
2016-05-18 15:42 ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).