All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cosmin Tanislav <demonsingur@gmail.com>
To: Guenter Roeck <linux@roeck-us.net>
Cc: cosmin.tanislav@analog.com, Jean Delvare <jdelvare@suse.com>,
	Jonathan Corbet <corbet@lwn.net>,
	linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/1] hwmon: Add debugfs register access
Date: Tue, 28 Dec 2021 18:51:40 +0200	[thread overview]
Message-ID: <9b82bdf9-25a0-46cd-cfed-b86f114dc303@gmail.com> (raw)
In-Reply-To: <b8dbcf50-8478-02c0-7a94-ff5b2b04aa2e@roeck-us.net>



On 12/28/21 18:13, Guenter Roeck wrote:
> On 12/27/21 2:42 PM, Cosmin Tanislav wrote:
>> From: Cosmin Tanislav <cosmin.tanislav@analog.com>
>>
>> Similar to IIO, create a device directory inside debugfs
>> mount point, and create a direct_reg_access file inside
>> that directory, if debugfs_reg_access callback is defined
>> inside hwmon_ops.
>>
> 
> Patch looks good afaics. I don't want to apply it now (ie for 5.17),
> though, because it is getting close and we don't have a use case.
> If you have one in mind, I'd suggest to submit it together with
> this patch, or we'll have to wait until there is a user.
> 
> Guenter

As I mentioned previously I have a local patch on top of the ADT7X10
refactor that uses this. I tested your modifications to my patchset on
the ADT7420 part and it seems to work just fine. I can push it on top of
either this patch or that patchset, your choice.

> 
>> Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
>> ---
>>   Documentation/hwmon/hwmon-kernel-api.rst |  9 +++
>>   drivers/hwmon/hwmon.c                    | 97 ++++++++++++++++++++++++
>>   include/linux/hwmon.h                    | 12 +++
>>   3 files changed, 118 insertions(+)
>>
>> diff --git a/Documentation/hwmon/hwmon-kernel-api.rst 
>> b/Documentation/hwmon/hwmon-kernel-api.rst
>> index c41eb6108103..d568a0bfa5fb 100644
>> --- a/Documentation/hwmon/hwmon-kernel-api.rst
>> +++ b/Documentation/hwmon/hwmon-kernel-api.rst
>> @@ -136,6 +136,8 @@ The list of hwmon operations is defined as::
>>               u32 attr, int, long *);
>>       int (*write)(struct device *, enum hwmon_sensor_types type,
>>                u32 attr, int, long);
>> +    int (*reg_access)(struct device *dev, unsigned int reg,
>> +              unsigned int writeval, unsigned int *readval);
>>     };
>>   It defines the following operations.
>> @@ -152,6 +154,13 @@ It defines the following operations.
>>       Pointer to a function for writing a value to the chip. This 
>> function is
>>       optional, but must be provided if any writeable attributes exist.
>> +* reg_access:
>> +    Pointer to a function for writing or reading a register to the chip.
>> +    This function is optional.
>> +    WARNING: Drivers implementing this function must block any access 
>> that
>> +    may cause issues such as power loss, board resets, flash 
>> corruption or
>> +    bricking.
>> +
>>   Each sensor channel is described with struct hwmon_channel_info, 
>> which is
>>   defined as follows::
>> diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
>> index 3501a3ead4ba..027e5fc33114 100644
>> --- a/drivers/hwmon/hwmon.c
>> +++ b/drivers/hwmon/hwmon.c
>> @@ -10,6 +10,7 @@
>>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>   #include <linux/bitops.h>
>> +#include <linux/debugfs.h>
>>   #include <linux/device.h>
>>   #include <linux/err.h>
>>   #include <linux/gfp.h>
>> @@ -35,6 +36,9 @@ struct hwmon_device {
>>       struct list_head tzdata;
>>       struct attribute_group group;
>>       const struct attribute_group **groups;
>> +    unsigned int cached_reg_addr;
>> +    char read_buf[20];
>> +    unsigned int read_buf_len;
>>   };
>>   #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
>> @@ -64,6 +68,90 @@ struct hwmon_thermal_data {
>>       struct thermal_zone_device *tzd;/* thermal zone device */
>>   };
>> +static struct dentry *hwmon_debugfs_dentry;
>> +
>> +static ssize_t hwmon_debugfs_read_reg(struct file *file,
>> +                      char __user *userbuf,
>> +                      size_t count, loff_t *ppos)
>> +{
>> +    struct hwmon_device *hwdev = file->private_data;
>> +    unsigned int val;
>> +    int ret;
>> +
>> +    if (*ppos > 0)
>> +        return simple_read_from_buffer(userbuf, count, ppos,
>> +                           hwdev->read_buf,
>> +                           hwdev->read_buf_len);
>> +
>> +    ret = hwdev->chip->ops->reg_access(&hwdev->dev, 
>> hwdev->cached_reg_addr,
>> +                       0, &val);
>> +    if (ret)
>> +        return ret;
>> +
>> +    hwdev->read_buf_len = snprintf(hwdev->read_buf, 
>> sizeof(hwdev->read_buf),
>> +                       "0x%X\n", val);
>> +
>> +    return simple_read_from_buffer(userbuf, count, ppos, 
>> hwdev->read_buf,
>> +                       hwdev->read_buf_len);
>> +}
>> +
>> +static ssize_t hwmon_debugfs_write_reg(struct file *file,
>> +                       const char __user *userbuf,
>> +                       size_t count, loff_t *ppos)
>> +{
>> +    struct hwmon_device *hwdev = file->private_data;
>> +    unsigned int reg, val;
>> +    char buf[80];
>> +    int ret;
>> +
>> +    count = min_t(size_t, count, sizeof(buf) - 1);
>> +    if (copy_from_user(buf, userbuf, count))
>> +        return -EFAULT;
>> +
>> +    buf[count] = 0;
>> +
>> +    ret = sscanf(buf, "%i %i", &reg, &val);
>> +
>> +    switch (ret) {
>> +    case 1:
>> +        hwdev->cached_reg_addr = reg;
>> +        break;
>> +    case 2:
>> +        hwdev->cached_reg_addr = reg;
>> +        ret = hwdev->chip->ops->reg_access(&hwdev->dev, reg, val, NULL);
>> +        if (ret)
>> +            return ret;
>> +        break;
>> +    default:
>> +        return -EINVAL;
>> +    }
>> +
>> +    return count;
>> +}
>> +
>> +static const struct file_operations hwmon_debugfs_reg_fops = {
>> +    .open = simple_open,
>> +    .read = hwmon_debugfs_read_reg,
>> +    .write = hwmon_debugfs_write_reg,
>> +};
>> +
>> +static void hwmon_device_register_debugfs(struct hwmon_device *hwdev)
>> +{
>> +    struct dentry *dir = debugfs_create_dir(dev_name(&hwdev->dev),
>> +                        hwmon_debugfs_dentry);
>> +
>> +    debugfs_create_file("direct_reg_access", 0644, dir, hwdev,
>> +                &hwmon_debugfs_reg_fops);
>> +}
>> +
>> +static void hwmon_device_unregister_debugfs(struct hwmon_device *hwdev)
>> +{
>> +    struct dentry *dir = debugfs_lookup(dev_name(&hwdev->dev),
>> +                        hwmon_debugfs_dentry);
>> +
>> +    debugfs_remove_recursive(dir);
>> +}
>> +
>>   static ssize_t
>>   name_show(struct device *dev, struct device_attribute *attr, char *buf)
>>   {
>> @@ -114,6 +202,8 @@ static void hwmon_dev_release(struct device *dev)
>>   {
>>       struct hwmon_device *hwdev = to_hwmon_device(dev);
>> +    hwmon_device_unregister_debugfs(hwdev);
>> +
>>       if (hwdev->group.attrs)
>>           hwmon_free_attrs(hwdev->group.attrs);
>>       kfree(hwdev->groups);
>> @@ -817,6 +907,9 @@ __hwmon_device_register(struct device *dev, const 
>> char *name, void *drvdata,
>>           }
>>       }
>> +    if (chip && chip->ops->reg_access)
>> +        hwmon_device_register_debugfs(hwdev);
>> +
>>       return hdev;
>>   free_hwmon:
>> @@ -1062,12 +1155,16 @@ static int __init hwmon_init(void)
>>           pr_err("couldn't register hwmon sysfs class\n");
>>           return err;
>>       }
>> +
>> +    hwmon_debugfs_dentry = debugfs_create_dir("hwmon", NULL);
>> +
>>       return 0;
>>   }
>>   static void __exit hwmon_exit(void)
>>   {
>>       class_unregister(&hwmon_class);
>> +    debugfs_remove(hwmon_debugfs_dentry);
>>   }
>>   subsys_initcall(hwmon_init);
>> diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
>> index fad1f1df26df..587fb2931ac1 100644
>> --- a/include/linux/hwmon.h
>> +++ b/include/linux/hwmon.h
>> @@ -390,6 +390,16 @@ enum hwmon_intrusion_attributes {
>>    *            Channel number
>>    *        @val:    Value to write
>>    *        The function returns 0 on success or a negative error number.
>> + * @reg_access:
>> + *        Callback to read or write register values.
>> + *        Parameters are:
>> + *        @dev:    Pointer to hardware monitoring device
>> + *        @reg:    Register address to read or write
>> + *        @writeval:
>> + *            Value to write to register. 0 when reading.
>> + *        @readval:
>> + *            Pointer to value read from register. NULL when writing.
>> + *        The function returns 0 on success or a negative error number.
>>    */
>>   struct hwmon_ops {
>>       umode_t (*is_visible)(const void *drvdata, enum 
>> hwmon_sensor_types type,
>> @@ -400,6 +410,8 @@ struct hwmon_ops {
>>               u32 attr, int channel, const char **str);
>>       int (*write)(struct device *dev, enum hwmon_sensor_types type,
>>                u32 attr, int channel, long val);
>> +    int (*reg_access)(struct device *dev, unsigned int reg,
>> +              unsigned int writeval, unsigned int *readval);
>>   };
>>   /**
>>
> 

  reply	other threads:[~2021-12-28 16:51 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-27 22:42 [PATCH v2 0/1] Add hwmon debugfs register access Cosmin Tanislav
2021-12-27 22:42 ` [PATCH v2 1/1] hwmon: Add " Cosmin Tanislav
2021-12-28 16:13   ` Guenter Roeck
2021-12-28 16:51     ` Cosmin Tanislav [this message]
2021-12-28 17:09       ` 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=9b82bdf9-25a0-46cd-cfed-b86f114dc303@gmail.com \
    --to=demonsingur@gmail.com \
    --cc=corbet@lwn.net \
    --cc=cosmin.tanislav@analog.com \
    --cc=jdelvare@suse.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@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.