diff mbox series

[2/2] drivers: hwmon: max31827: Add debugfs support

Message ID 20240522123923.22320-3-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 debugfs support by creating directory in sys-fs which includes
debugfs specific files used for configuring the device by
preference.

Signed-off-b: Radu Sabau <radu.sabau@analog.com>
---
 Documentation/hwmon/max31827.rst |  25 ++++
 drivers/hwmon/max31827.c         | 202 ++++++++++++++++++++++++++++++-
 2 files changed, 225 insertions(+), 2 deletions(-)

Comments

Nuno Sá May 22, 2024, 1:10 p.m. UTC | #1
On Wed, 2024-05-22 at 15:39 +0300, Radu Sabau wrote:
> Add debugfs support by creating directory in sys-fs which includes
> debugfs specific files used for configuring the device by
> preference.
> 
> Signed-off-b: Radu Sabau <radu.sabau@analog.com>
> ---
>  Documentation/hwmon/max31827.rst |  25 ++++
>  drivers/hwmon/max31827.c         | 202 ++++++++++++++++++++++++++++++-
>  2 files changed, 225 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst
> index 9c11a9518c67..940310be6075 100644
> --- a/Documentation/hwmon/max31827.rst
> +++ b/Documentation/hwmon/max31827.rst
> @@ -142,3 +142,28 @@ usage (+33% for both write and reads) in normal conditions.
>  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.
> +
> +DebugFs entries
> +---------------
> +
> +The chip also has a configuration register where each bit stands for a specific
> +functionality to be configured. Hence as one would like to have access to these
> +features, we give access to them in debugfs.
> +
> +.. warning:: The debugfs interface is subject to change without notice
> +             and is only available when the kernel is compiled with
> +             ``CONFIG_DEBUG_FS`` defined.
> +
> +``/sys/kernel/debug/max31827/``
> +contains the following attributes:
> +
> +==============  ===============================================================
> +alarm_polarity  Write 1 for ALARM pin active state is low, 0 otherwise
> +comp_int        Set to 1 if OT and UT status bits are in interrupt mode
> +fault_queue     Number of consecutive temperature faults until OT and UT faults
> +                are indicated in status bits
> +pec_error       Set to 1 if PEC Enable bit is set, 0 otherwise
> +resolution      2-bit value that select the conversion resolution, please see
> +                datasheet for corresponding values
> +timeout         Write 1 do disable bus timeout, 0 otherwise

From the description, the above really don't look like they belong into a debug
interface...

- Nuno Sá
>
Guenter Roeck May 23, 2024, 4:53 a.m. UTC | #2
On 5/22/24 06:10, Nuno Sá wrote:
> On Wed, 2024-05-22 at 15:39 +0300, Radu Sabau wrote:
>> Add debugfs support by creating directory in sys-fs which includes
>> debugfs specific files used for configuring the device by
>> preference.
>>
>> Signed-off-b: Radu Sabau <radu.sabau@analog.com>
>> ---
>>   Documentation/hwmon/max31827.rst |  25 ++++
>>   drivers/hwmon/max31827.c         | 202 ++++++++++++++++++++++++++++++-
>>   2 files changed, 225 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst
>> index 9c11a9518c67..940310be6075 100644
>> --- a/Documentation/hwmon/max31827.rst
>> +++ b/Documentation/hwmon/max31827.rst
>> @@ -142,3 +142,28 @@ usage (+33% for both write and reads) in normal conditions.
>>   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.
>> +
>> +DebugFs entries
>> +---------------
>> +
>> +The chip also has a configuration register where each bit stands for a specific
>> +functionality to be configured. Hence as one would like to have access to these
>> +features, we give access to them in debugfs.
>> +
>> +.. warning:: The debugfs interface is subject to change without notice
>> +             and is only available when the kernel is compiled with
>> +             ``CONFIG_DEBUG_FS`` defined.
>> +
>> +``/sys/kernel/debug/max31827/``
>> +contains the following attributes:
>> +
>> +==============  ===============================================================
>> +alarm_polarity  Write 1 for ALARM pin active state is low, 0 otherwise
>> +comp_int        Set to 1 if OT and UT status bits are in interrupt mode
>> +fault_queue     Number of consecutive temperature faults until OT and UT faults
>> +                are indicated in status bits
>> +pec_error       Set to 1 if PEC Enable bit is set, 0 otherwise
>> +resolution      2-bit value that select the conversion resolution, please see
>> +                datasheet for corresponding values
>> +timeout         Write 1 do disable bus timeout, 0 otherwise
> 
>>From the description, the above really don't look like they belong into a debug
> interface...
> 

Correct. The chip should be configured using firmware properties, which for the
most part is already supported. An acceptable exception is PEC, but that
configuration flag, if implemented as attribute, should be attached to the
i2c client interface to match other drivers.

Guenter
diff mbox series

Patch

diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst
index 9c11a9518c67..940310be6075 100644
--- a/Documentation/hwmon/max31827.rst
+++ b/Documentation/hwmon/max31827.rst
@@ -142,3 +142,28 @@  usage (+33% for both write and reads) in normal conditions.
 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.
+
+DebugFs entries
+---------------
+
+The chip also has a configuration register where each bit stands for a specific
+functionality to be configured. Hence as one would like to have access to these
+features, we give access to them in debugfs.
+
+.. warning:: The debugfs interface is subject to change without notice
+             and is only available when the kernel is compiled with
+             ``CONFIG_DEBUG_FS`` defined.
+
+``/sys/kernel/debug/max31827/``
+contains the following attributes:
+
+==============  ===============================================================
+alarm_polarity  Write 1 for ALARM pin active state is low, 0 otherwise
+comp_int        Set to 1 if OT and UT status bits are in interrupt mode
+fault_queue     Number of consecutive temperature faults until OT and UT faults
+                are indicated in status bits
+pec_error       Set to 1 if PEC Enable bit is set, 0 otherwise
+resolution      2-bit value that select the conversion resolution, please see
+                datasheet for corresponding values
+timeout         Write 1 do disable bus timeout, 0 otherwise
+==============  ===============================================================
diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c
index 16a1524413db..1303ea81250d 100644
--- a/drivers/hwmon/max31827.c
+++ b/drivers/hwmon/max31827.c
@@ -13,8 +13,19 @@ 
 #include <linux/mutex.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/debugfs.h>
 #include <linux/of_device.h>
 
+enum {
+	MAX31827_DEBUGFS_TIMEOUT = 0,
+	MAX31827_DEBUGFS_RESOLUTION,
+	MAX31827_DEBUGFS_ALARM_POLARITY,
+	MAX31827_DEBUGFS_COMP_INT,
+	MAX31827_DEBUGFS_FAULT_QUEUE,
+	MAX31827_DEBUGFS_PEC_ERROR,
+	MAX31827_DEBUGFS_NUM_ENTRIES
+};
+
 #define MAX31827_T_REG	0x0
 #define MAX31827_CONFIGURATION_REG	0x2
 #define MAX31827_TH_REG	0x4
@@ -30,6 +41,7 @@ 
 #define MAX31827_CONFIGURATION_ALRM_POL_MASK	BIT(8)
 #define MAX31827_CONFIGURATION_COMP_INT_MASK	BIT(9)
 #define MAX31827_CONFIGURATION_FLT_Q_MASK	GENMASK(11, 10)
+#define MAX31827_CONFIGURATION_PEC_ERR_MASK	BIT(13)
 #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK	BIT(14)
 #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK	BIT(15)
 
@@ -92,12 +104,17 @@  static const u16 max31827_conv_times[] = {
 	[MAX31827_RES_12_BIT] = MAX31827_12_BIT_CNV_TIME,
 };
 
+struct max31827_debugfs_data {
+	int debugfs_entries[MAX31827_DEBUGFS_NUM_ENTRIES];
+};
+
 struct max31827_state {
 	/*
 	 * Prevent simultaneous access to the i2c client.
 	 */
 	struct mutex lock;
 	struct regmap *regmap;
+	struct max31827_debugfs_data psu;
 	bool enable;
 	unsigned int resolution;
 	unsigned int update_interval;
@@ -552,7 +569,6 @@  static int max31827_init_client(struct max31827_state *st,
 	int ret;
 
 	fwnode = dev_fwnode(dev);
-
 	st->enable = true;
 	res |= MAX31827_DEVICE_ENABLE(1);
 
@@ -655,6 +671,182 @@  static const struct hwmon_chip_info max31827_chip_info = {
 	.info = max31827_info,
 };
 
+#ifdef CONFIG_DEBUG_FS
+static ssize_t max31827_debugfs_read(struct file *file, char __user *buf,
+				     size_t count, loff_t *ppos)
+{
+	char tbuf[DEBUG_FS_DATA_MAX] = { 0 };
+	struct max31827_debugfs_data *psu;
+	struct max31827_state *st;
+	int *attrp = file_inode(file)->i_private;
+	int attr = *attrp;
+	unsigned int uval;
+	int ret, len;
+
+	psu = container_of(attrp, struct max31827_debugfs_data, debugfs_entries[attr]);
+	st = container_of(psu, struct max31827_state, psu);
+
+	ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &uval);
+	if (ret)
+		return ret;
+
+	switch (attr) {
+	case MAX31827_DEBUGFS_TIMEOUT:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_TIMEOUT_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	case MAX31827_DEBUGFS_RESOLUTION:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	case MAX31827_DEBUGFS_ALARM_POLARITY:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_ALRM_POL_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	case MAX31827_DEBUGFS_COMP_INT:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_COMP_INT_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	case MAX31827_DEBUGFS_FAULT_QUEUE:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_FLT_Q_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	case MAX31827_DEBUGFS_PEC_ERROR:
+		uval = FIELD_GET(MAX31827_CONFIGURATION_PEC_ERR_MASK, uval);
+		len = scnprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", uval);
+		break;
+	default:
+		len = strscpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
+	}
+
+	return simple_read_from_buffer(buf, count, ppos, tbuf, len);
+}
+
+static ssize_t max31827_debugfs_write(struct file *file, const char __user *buf,
+				      size_t count, loff_t *ppos)
+{
+	char tbuf[DEBUG_FS_DATA_MAX] = { 0 };
+	struct max31827_debugfs_data *psu;
+	struct max31827_state *st;
+	int *attrp = file_inode(file)->i_private;
+	int attr = *attrp;
+	u16 uval;
+	int ret;
+
+	pr_info("attr = %d\n", attr);
+	psu = container_of(attrp, struct max31827_debugfs_data, debugfs_entries[attr]);
+	pr_info("First container ok.\n");
+	st = container_of(psu, struct max31827_state, psu);
+
+	ret = kstrtou16_from_user(buf, count, 0, &uval);
+	if (ret)
+		return ret;
+
+	pr_info("uval = %s\n", tbuf);
+
+	switch (attr) {
+	case MAX31827_DEBUGFS_TIMEOUT:
+		uval = FIELD_PREP(MAX31827_CONFIGURATION_TIMEOUT_MASK, uval);
+		ret = regmap_update_bits(st->regmap,
+					 MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_TIMEOUT_MASK,
+					 uval);
+		break;
+	case MAX31827_DEBUGFS_RESOLUTION:
+		uval = FIELD_PREP(MAX31827_CONFIGURATION_RESOLUTION_MASK, uval);
+		ret = regmap_update_bits(st->regmap,
+					 MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_RESOLUTION_MASK,
+					 uval);
+		break;
+	case MAX31827_DEBUGFS_ALARM_POLARITY:
+		uval = FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, uval);
+		ret = regmap_update_bits(st->regmap,
+					 MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_ALRM_POL_MASK,
+					 uval);
+		break;
+	case MAX31827_DEBUGFS_COMP_INT:
+		uval = FIELD_PREP(MAX31827_CONFIGURATION_COMP_INT_MASK, uval);
+		ret = regmap_update_bits(st->regmap,
+					 MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_COMP_INT_MASK,
+					 uval);
+		break;
+	case MAX31827_DEBUGFS_FAULT_QUEUE:
+		uval = FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, uval);
+		ret = regmap_update_bits(st->regmap,
+					 MAX31827_CONFIGURATION_REG,
+					 MAX31827_CONFIGURATION_FLT_Q_MASK,
+					 uval);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations max31827_fops = {
+	.read = max31827_debugfs_read,
+	.write = max31827_debugfs_write,
+};
+
+static void max31827_debugfs_remove(void *dir)
+{
+	debugfs_remove_recursive(dir);
+}
+
+static int max31827_init_debugfs(struct max31827_state *st,
+				 struct i2c_client *client)
+{
+	struct dentry *debugfs;
+	int ret, i;
+
+	debugfs = debugfs_create_dir(client->name, NULL);
+	if (!debugfs)
+		return -ENOENT;
+
+	for (i = 0; i < MAX31827_DEBUGFS_NUM_ENTRIES; ++i)
+		st->psu.debugfs_entries[i] = i;
+
+	ret = devm_add_action_or_reset(&client->dev, max31827_debugfs_remove,
+				       debugfs);
+	if (ret)
+		return ret;
+
+	debugfs_create_file("timeout", 0644, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_TIMEOUT],
+			    &max31827_fops);
+	debugfs_create_file("resolution", 0644, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_RESOLUTION],
+			    &max31827_fops);
+	debugfs_create_file("alarm_polarity", 0644, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_ALARM_POLARITY],
+			    &max31827_fops);
+	debugfs_create_file("comp_int", 0644, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_COMP_INT],
+			    &max31827_fops);
+	debugfs_create_file("fault_queue", 0644, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_FAULT_QUEUE],
+			    &max31827_fops);
+	debugfs_create_file("pec_error", 0444, debugfs,
+			    &st->psu.debugfs_entries[MAX31827_DEBUGFS_PEC_ERROR],
+			    &max31827_fops);
+
+	return 0;
+}
+#else
+static int max31827_init_debugfs(struct max31827_state *st,
+				 struct i2c_client *client)
+{
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
 static int max31827_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
@@ -698,7 +890,13 @@  static int max31827_probe(struct i2c_client *client)
 							 &max31827_chip_info,
 							 max31827_groups);
 
-	return PTR_ERR_OR_ZERO(hwmon_dev);
+	if (IS_ERR(hwmon_dev))
+		return dev_err_probe(dev, PTR_ERR(hwmon_dev),
+				     "Failed to register device");
+
+	max31827_init_debugfs(st, client);
+
+	return 0;
 }
 
 static const struct of_device_id max31827_of_match[] = {