[PATCH 1/2] drivers: hwmon: max31827: Add PEC support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for PEC by attaching PEC attribute to the i2c device.
Add pec_store and pec_show function for accesing the "pec" file.

Signed-off-by: Radu Sabau <radu.sabau@xxxxxxxxxx>
---
 Documentation/hwmon/max31827.rst | 13 ++++-
 drivers/hwmon/max31827.c         | 95 +++++++++++++++++++++++++++-----
 2 files changed, 92 insertions(+), 16 deletions(-)

diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst
index 44ab9dc064cb..9c11a9518c67 100644
--- a/Documentation/hwmon/max31827.rst
+++ b/Documentation/hwmon/max31827.rst
@@ -131,7 +131,14 @@ The Fault Queue bits select how many consecutive temperature faults must occur
 before overtemperature or undertemperature faults are indicated in the
 corresponding status bits.
 
-Notes
------
+PEC Support
+-----------
+
+When reading a register value, the PEC byte is computed and sent by the chip.
+
+PEC on word data transaction respresents a signifcant increase in bandwitdh
+usage (+33% for both write and reads) in normal conditions.
 
-PEC is not implemented.
+Since this operation implies there will be an extra delay to each
+transaction, PEC can be disabled or enabled through sysfs.
+Just write 1  to the "pec" file for enabling PEC and 0 for disabling it.
diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c
index f8a13b30f100..16a1524413db 100644
--- a/drivers/hwmon/max31827.c
+++ b/drivers/hwmon/max31827.c
@@ -11,19 +11,20 @@
 #include <linux/hwmon.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
-#include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
 
-#define MAX31827_T_REG			0x0
+#define MAX31827_T_REG	0x0
 #define MAX31827_CONFIGURATION_REG	0x2
-#define MAX31827_TH_REG			0x4
-#define MAX31827_TL_REG			0x6
-#define MAX31827_TH_HYST_REG		0x8
-#define MAX31827_TL_HYST_REG		0xA
+#define MAX31827_TH_REG	0x4
+#define MAX31827_TL_REG 0x6
+#define MAX31827_TH_HYST_REG	0x8
+#define MAX31827_TL_HYST_REG	0xA
 
 #define MAX31827_CONFIGURATION_1SHOT_MASK	BIT(0)
 #define MAX31827_CONFIGURATION_CNV_RATE_MASK	GENMASK(3, 1)
+#define MAX31827_CONFIGURATION_PEC_EN_MASK	BIT(4)
 #define MAX31827_CONFIGURATION_TIMEOUT_MASK	BIT(5)
 #define MAX31827_CONFIGURATION_RESOLUTION_MASK	GENMASK(7, 6)
 #define MAX31827_CONFIGURATION_ALRM_POL_MASK	BIT(8)
@@ -46,6 +47,8 @@
 #define MAX31827_M_DGR_TO_16_BIT(x)	(((x) << 4) / 1000)
 #define MAX31827_DEVICE_ENABLE(x)	((x) ? 0xA : 0x0)
 
+#define DEBUG_FS_DATA_MAX	16
+
 enum chips { max31827 = 1, max31828, max31829 };
 
 enum max31827_cnv {
@@ -151,8 +154,8 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg,
 		goto unlock;
 
 	ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
-				 MAX31827_CONFIGURATION_CNV_RATE_MASK,
-				 cnv_rate);
+				   MAX31827_CONFIGURATION_CNV_RATE_MASK,
+				   cnv_rate);
 
 unlock:
 	mutex_unlock(&st->lock);
@@ -344,7 +347,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
 		switch (attr) {
 		case hwmon_temp_enable:
 			if (val >> 1)
-				return -EINVAL;
+				return -EOPNOTSUPP;
 
 			mutex_lock(&st->lock);
 			/**
@@ -384,7 +387,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
 	case hwmon_chip:
 		if (attr == hwmon_chip_update_interval) {
 			if (!st->enable)
-				return -EINVAL;
+				return -EOPNOTSUPP;
 
 			/*
 			 * Convert the desired conversion rate into register
@@ -472,11 +475,60 @@ static ssize_t temp1_resolution_store(struct device *dev,
 
 	return ret ? ret : count;
 }
-
 static DEVICE_ATTR_RW(temp1_resolution);
 
+static ssize_t pec_show(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
+}
+
+static ssize_t pec_store(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	struct max31827_state *st = dev_get_drvdata(dev);
+	struct i2c_client *client = to_i2c_client(dev);
+	unsigned int val, val2;
+	int err;
+
+	err = kstrtouint(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val2 = FIELD_PREP(MAX31827_CONFIGURATION_PEC_EN_MASK, !!val);
+
+	switch (val) {
+	case 0:
+		err = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_PEC_EN_MASK,
+					 val2);
+		if (err)
+			return err;
+
+		client->flags &= ~I2C_CLIENT_PEC;
+		break;
+	case 1:
+		err = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_PEC_EN_MASK,
+					 val2);
+		if (err)
+			return err;
+
+		client->flags |= I2C_CLIENT_PEC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+static DEVICE_ATTR_RW(pec);
+
 static struct attribute *max31827_attrs[] = {
 	&dev_attr_temp1_resolution.attr,
+	&dev_attr_pec.attr,
 	NULL
 };
 ATTRIBUTE_GROUPS(max31827);
@@ -493,8 +545,8 @@ static int max31827_init_client(struct max31827_state *st,
 				struct device *dev)
 {
 	struct fwnode_handle *fwnode;
+	unsigned int data, lsb_idx;
 	unsigned int res = 0;
-	u32 data, lsb_idx;
 	enum chips type;
 	bool prop;
 	int ret;
@@ -578,6 +630,11 @@ static int max31827_init_client(struct max31827_state *st,
 	return regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, res);
 }
 
+static void max31827_remove_pec(void *dev)
+{
+	device_remove_file(dev, &dev_attr_pec);
+}
+
 static const struct hwmon_channel_info *max31827_info[] = {
 	HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN |
 					 HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM |
@@ -627,6 +684,16 @@ static int max31827_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) {
+		err = device_create_file(dev, &dev_attr_pec);
+		if (err)
+			return err;
+
+		err = devm_add_action_or_reset(dev, max31827_remove_pec, dev);
+		if (err)
+			return err;
+	}
+
 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
 							 &max31827_chip_info,
 							 max31827_groups);
@@ -652,15 +719,17 @@ static const struct of_device_id max31827_of_match[] = {
 MODULE_DEVICE_TABLE(of, max31827_of_match);
 
 static struct i2c_driver max31827_driver = {
+	.class = I2C_CLASS_HWMON,
 	.driver = {
 		.name = "max31827",
 		.of_match_table = max31827_of_match,
 	},
-	.probe = max31827_probe,
+	.probe_new = max31827_probe,
 	.id_table = max31827_i2c_ids,
 };
 module_i2c_driver(max31827_driver);
 
 MODULE_AUTHOR("Daniel Matyas <daniel.matyas@xxxxxxxxxx>");
+MODULE_AUTHOR("Radu Sabau <radu.sabau@xxxxxxxxxx>");
 MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
 MODULE_LICENSE("GPL");
-- 
2.34.1





[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux