diff mbox series

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

Message ID 20240522123923.22320-2-radu.sabau@analog.com (mailing list archive)
State Superseded
Headers show
Series Update MAX31827 driver | expand

Commit Message

Radu Sabau May 22, 2024, 12:39 p.m. UTC
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@analog.com>
---
 Documentation/hwmon/max31827.rst | 13 ++++-
 drivers/hwmon/max31827.c         | 95 +++++++++++++++++++++++++++-----
 2 files changed, 92 insertions(+), 16 deletions(-)

Comments

Nuno Sá May 22, 2024, 1:08 p.m. UTC | #1
On Wed, 2024-05-22 at 15:39 +0300, Radu Sabau wrote:
> 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@analog.com>
> ---
>  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>
>  

Looks like unrelated change...
> -#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

ditto for all the other places

...

>  
> +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));

sysfs_emit()

> +}
> +
> +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);
> +

Why not just 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,

Do we need it in here??


- Nuno Sá
kernel test robot May 23, 2024, 4:37 a.m. UTC | #2
Hi Radu,

kernel test robot noticed the following build errors:

[auto build test ERROR on groeck-staging/hwmon-next]
[also build test ERROR on linus/master v6.9 next-20240523]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Radu-Sabau/drivers-hwmon-max31827-Add-PEC-support/20240523-004248
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
patch link:    https://lore.kernel.org/r/20240522123923.22320-2-radu.sabau%40analog.com
patch subject: [PATCH 1/2] drivers: hwmon: max31827: Add PEC support
config: i386-buildonly-randconfig-003-20240523 (https://download.01.org/0day-ci/archive/20240523/202405231257.IOuSANzt-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240523/202405231257.IOuSANzt-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405231257.IOuSANzt-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/hwmon/max31827.c:727:3: error: field designator 'probe_new' does not refer to any field in type 'struct i2c_driver'
     727 |         .probe_new = max31827_probe,
         |         ~^~~~~~~~~~~~~~~~~~~~~~~~~~
   1 error generated.


vim +727 drivers/hwmon/max31827.c

   720	
   721	static struct i2c_driver max31827_driver = {
   722		.class = I2C_CLASS_HWMON,
   723		.driver = {
   724			.name = "max31827",
   725			.of_match_table = max31827_of_match,
   726		},
 > 727		.probe_new = max31827_probe,
   728		.id_table = max31827_i2c_ids,
   729	};
   730	module_i2c_driver(max31827_driver);
   731
Guenter Roeck May 23, 2024, 5:11 a.m. UTC | #3
On 5/22/24 05:39, Radu Sabau wrote:
> Add support for PEC by attaching PEC attribute to the i2c device.
> Add pec_store and pec_show function for accesing the "pec" file.
> 
accessing

> Signed-off-by: Radu Sabau <radu.sabau@analog.com>
> ---

There are lots of unrelated changes. Please drop all those, or
if they are supposed to fix checkpatch problems submit as separate
patches. I will not accept coding style changes unless they fix
checkpatch problems.

The patch is not based on the latest kernel. Please rebase
at least on top of v6.9.

More comments inline.

>   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>
>   

Include files should be in alphabetic order. The above change
deserves a NACK.

> -#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;

Why ?

>   
>   			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);

This is completely unnecessary.

> +
> +	switch (val) {
> +	case 0:
> +		err = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
> +					 MAX31827_CONFIGURATION_PEC_EN_MASK,
> +					 val2);

	s/val2/0/

> +		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);

	s/val2/MAX31827_CONFIGURATION_PEC_EN_MASK/

> +		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,

Attach to i2c interface.

Oh, wait, you are doing that as well. So there would be two
"pec" attribute files, one attached to the i2c interface
and one attached to the hwmon interface. Care to explain ?

>   	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;

I am quite completely at loss trying to understand why you are making those changes.

>   	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)) {

This does not make sense. If the controller does not support PEC,
it does not make sense to provide an attribute to enable it.

> +		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@analog.com>");
> +MODULE_AUTHOR("Radu Sabau <radu.sabau@analog.com>");

Providing a patch to a driver does not make you the author.

>   MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
>   MODULE_LICENSE("GPL");
diff mbox series

Patch

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@analog.com>");
+MODULE_AUTHOR("Radu Sabau <radu.sabau@analog.com>");
 MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
 MODULE_LICENSE("GPL");