From patchwork Wed Oct 10 04:33:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10633949 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E78E013AD for ; Wed, 10 Oct 2018 04:33:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CB6152928B for ; Wed, 10 Oct 2018 04:33:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BE7E529307; Wed, 10 Oct 2018 04:33:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 23A022928B for ; Wed, 10 Oct 2018 04:33:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727218AbeJJLxf (ORCPT ); Wed, 10 Oct 2018 07:53:35 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:40710 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726582AbeJJLxe (ORCPT ); Wed, 10 Oct 2018 07:53:34 -0400 Received: by mail-pg1-f194.google.com with SMTP id n31-v6so1877595pgm.7; Tue, 09 Oct 2018 21:33:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=eWhd1Tb5PRU/lQ2NdschJnLbQwERZJCIHgKdwYaw3Tk=; b=kq2Zq6l9ofQilON/WuHr4oaiKb5NJ7T2fOJbLXs6aABsH8T45yafLMNJHsgyJZAhZo bDi94Nkx8YOW8ogX2HEyGV3ZzziRrgg8+x4UK0c8vzkwLTL+bYEXHlOHL4rgU90YoXhD bmFSTTrV7y1+wIE8vUbTSxT1uvVD/L0xykJJDkZPnTPlZYoYiUt9tGGg4aCjEQYKOkXh qZ9qMlI0hUHcG9Plsj995T4E0U3d4ugCKbiU8tJMIlPkHM8LDa21v32Z6xthYowN02V5 HIzUMq4J+ZWU+FYX9Ptq9EX6b6SmuQyb8sP24fodM1sbFVrrZtbOQCzpco+mAWB4Bf5v sqOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=eWhd1Tb5PRU/lQ2NdschJnLbQwERZJCIHgKdwYaw3Tk=; b=TqwFj6y4y8L5XBQxCLPh/LJqRXhxZjMbtCPmYMPBko0MdY1jLBvujE7z/jpnUj3r5V 8cNOfzKi7wP1yR37j3z+GQrdNn9rohEJhqHowL7/USIjEjxlYLR62u/vgSxvkWNohAAH m0m6Wo9vv7hNigdEPsagKDJ/YWHy5vyNVWD92uc68XOuc9mMAChbOPURWWzzIzjT5LPe sExsby5mO5PD1kFuWX7xFl5z8HNmP4oQVDJKO8H+sz6gPufIiylEYcZ+tAIDlUgh4Isp oK/qY6/KeSTn9L+MX5Z/prr/FPAnWFxvX4ElNVnlH9KmDtWs+IPIkEsqFkKDouKKVa27 y1CQ== X-Gm-Message-State: ABuFfohbnI7mC6Ydg86s4gNCo7YrT5nvII7U6EGe6i+W8i56A0wWNsbl DcTqY5KlIvPd6UlRcxh3f+o= X-Google-Smtp-Source: ACcGV61AdqVL+jSbkmjArpFHAKUCmzMVq3gKaIO6dvY/Bn+9T/l7YDz0PV6tYJK1DjAn4EtBDhhORw== X-Received: by 2002:a63:64c2:: with SMTP id y185-v6mr27919661pgb.411.1539145998418; Tue, 09 Oct 2018 21:33:18 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id n63-v6sm21171025pfn.9.2018.10.09.21.33.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Oct 2018 21:33:17 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, corbet@lwn.net, linux-doc@vger.kernel.org Subject: [PATCH 1/2] hwmon: (core) Add hwmon_mode structure and mode sysfs node Date: Tue, 9 Oct 2018 21:33:09 -0700 Message-Id: <20181010043310.30873-2-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181010043310.30873-1-nicoleotsuka@gmail.com> References: <20181010043310.30873-1-nicoleotsuka@gmail.com> Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There are a few hwmon sensors support different operating modes, for example, one-shot and continuous modes. So it's probably not a bad idea to abstract a mode sysfs node as a common feature in the hwmon core. Right beside the hwmon device name, this patch adds a new sysfs attribute named "mode" and "available_modes" for user to check and configure the operating mode. For hwmon device drivers that implemented the _with_info API, the change also adds an optional hwmon_mode structure in hwmon_chip_info structure so that those drivers can pass mode related information. Signed-off-by: Nicolin Chen --- Documentation/hwmon/sysfs-interface | 15 +++++ drivers/hwmon/hwmon.c | 87 ++++++++++++++++++++++++++--- include/linux/hwmon.h | 24 ++++++++ 3 files changed, 119 insertions(+), 7 deletions(-) diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 2b9e1005d88b..48d6ca6b9bd4 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -92,6 +92,21 @@ name The chip name. I2C devices get this attribute created automatically. RO +available_modes The available operating modes of the chip. + This should be short, lowercase string, not containing + whitespace, or the wildcard character '*'. + This attribute shows all the available of the operating modes, + for example, "power-down" "one-shot" and "continuous". + RO + +mode The current operating mode of the chip. + This should be short, lowercase string, not containing + whitespace, or the wildcard character '*'. + This attribute shows the current operating mode of the chip. + Writing a valid string from the list of available_modes will + configure the chip to the corresponding operating mode. + RW + update_interval The interval at which the chip will update readings. Unit: millisecond RW diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 975c95169884..5a33b616284b 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -72,25 +72,88 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(name); +static ssize_t available_modes_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hwmon_device *hwdev = to_hwmon_device(dev); + const struct hwmon_chip_info *chip = hwdev->chip; + const struct hwmon_mode *mode = chip->mode; + int i; + + for (i = 0; i < mode->list_size; i++) + snprintf(buf, PAGE_SIZE, "%s%s ", buf, mode->names[i]); + + return snprintf(buf, PAGE_SIZE, "%s\n", buf); +} +static DEVICE_ATTR_RO(available_modes); + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hwmon_device *hwdev = to_hwmon_device(dev); + const struct hwmon_chip_info *chip = hwdev->chip; + const struct hwmon_mode *mode = chip->mode; + unsigned int index; + int ret; + + ret = mode->get_index(dev, &index); + if (ret) + return ret; + + return snprintf(buf, PAGE_SIZE, "%s\n", mode->names[index]); +} + +static ssize_t mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hwmon_device *hwdev = to_hwmon_device(dev); + const struct hwmon_chip_info *chip = hwdev->chip; + const struct hwmon_mode *mode = chip->mode; + const char **names = mode->names; + unsigned int index; + int ret; + + /* Get the corresponding mode index */ + for (index = 0; index < mode->list_size; index++) { + if (!strncmp(buf, names[index], strlen(names[index]))) + break; + } + + if (index >= mode->list_size) + return -EINVAL; + + ret = mode->set_index(dev, index); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_RW(mode); + static struct attribute *hwmon_dev_attrs[] = { - &dev_attr_name.attr, + &dev_attr_name.attr, /* index = 0 */ + &dev_attr_available_modes.attr, /* index = 1 */ + &dev_attr_mode.attr, /* index = 2 */ NULL }; -static umode_t hwmon_dev_name_is_visible(struct kobject *kobj, - struct attribute *attr, int n) +static umode_t hwmon_dev_is_visible(struct kobject *kobj, + struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); + struct hwmon_device *hwdev = to_hwmon_device(dev); - if (to_hwmon_device(dev)->name == NULL) - return 0; + if (n == 0 && hwdev->name) + return attr->mode; + else if (n <= 2 && hwdev->chip->mode) + return attr->mode; - return attr->mode; + return 0; } static const struct attribute_group hwmon_dev_attr_group = { .attrs = hwmon_dev_attrs, - .is_visible = hwmon_dev_name_is_visible, + .is_visible = hwmon_dev_is_visible, }; static const struct attribute_group *hwmon_dev_attr_groups[] = { @@ -591,6 +654,16 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, struct attribute **attrs; int ngroups = 2; /* terminating NULL plus &hwdev->groups */ + /* Validate optional hwmon_mode */ + if (chip->mode) { + /* Check mandatory properties */ + if (!chip->mode->names || !chip->mode->list_size || + !chip->mode->get_index || !chip->mode->set_index) { + err = -EINVAL; + goto free_hwmon; + } + } + if (groups) for (i = 0; groups[i]; i++) ngroups++; diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 99e0c1b0b5fb..06c1940ca98b 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -365,14 +365,38 @@ struct hwmon_channel_info { const u32 *config; }; +/** + * Chip operating mode information + * @names: A list of available operating mode names. + * @list_size: The total number of available operating mode names. + * @get_index: Callback to get current operating mode index. Mandatory. + * Parameters are: + * @dev: Pointer to hardware monitoring device + * @index: Pointer to returned mode index + * The function returns 0 on success or a negative error number. + * @set_index: Callback to set operating mode using the index. Mandatory. + * Parameters are: + * @dev: Pointer to hardware monitoring device + * @index: Mode index in the mode list + * The function returns 0 on success or a negative error number. + */ +struct hwmon_mode { + const char **names; + unsigned int list_size; + int (*get_index)(struct device *dev, unsigned int *index); + int (*set_index)(struct device *dev, unsigned int index); +}; + /** * Chip configuration * @ops: Pointer to hwmon operations. * @info: Null-terminated list of channel information. + * @mode: Pointer to hwmon operating mode (optional). */ struct hwmon_chip_info { const struct hwmon_ops *ops; const struct hwmon_channel_info **info; + const struct hwmon_mode *mode; }; /* hwmon_device_register() is deprecated */ From patchwork Wed Oct 10 04:33:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10633951 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AFFFB16B1 for ; Wed, 10 Oct 2018 04:33:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94F6F2928B for ; Wed, 10 Oct 2018 04:33:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 894B5292C6; Wed, 10 Oct 2018 04:33:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4EE90292A6 for ; Wed, 10 Oct 2018 04:33:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727298AbeJJLxg (ORCPT ); Wed, 10 Oct 2018 07:53:36 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:37128 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727215AbeJJLxf (ORCPT ); Wed, 10 Oct 2018 07:53:35 -0400 Received: by mail-pg1-f194.google.com with SMTP id c10-v6so1885337pgq.4; Tue, 09 Oct 2018 21:33:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=j2pcZhfoBUj85c/KvZuz0NI6wWCc4PRH6zbLnyObSGY=; b=qvFheePZmOo1c7AqPxlNV9R98QKObxP8G3ckJk3CPR/jI3Yp0/ure+Dtx2qaZCX6aE LVcKCrMNbHd3vsKar3Tx4o2Bx4tu/QUn6U4aNthdieG7PTtezojehA8407dglutf7H5f 4JKPaGYMXi+iOIlo/BUX/OEAEAoMaiXqU61UnCkB4yus+rNEI5swJTSNSuyaCokjtthD h76O7QBDKjWUW7Ja1wxj3V8f5qSb7tLCkjOThKMZuy+1iLmcJEhjhezEMQtrKL22Drol kNEKH73ZUoGpgDppZMW3dQMaFw6ECEQr89kW2fArCETT1mqI5fx0NS61Ba1s6UgWwD8Q avcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=j2pcZhfoBUj85c/KvZuz0NI6wWCc4PRH6zbLnyObSGY=; b=e4TZDn+569maCzy0LP5OLva7Ipjh1edUL+Ue2/W7Kccqeip+H1cfszJCXp8q7aKSKj 3HKnFWEpnDVlvpn64rhGblqr9D4qS7s5JfNoc73gUQ7Rqk9kpQNUxfRjIuYURkjqwx13 wLC3ikcLggk+sJMSqBRWYuFsuXa7e7xTny1IAZfoqetWfcYcJPhQP/mJF6KuIpK0wuKA B73e63Iot9ZLOlCSPSwgB9Ixp6lqmD07GXxsuZVsseRmeQiH1baNUb+SlKNt8QrC8109 cknL0SOVe1FepGxpTUAe8u0lB6OjN4Qfc+/cc8lBnWnYC0/OyvH2PT7AN1/TLz2DgJe+ L7sA== X-Gm-Message-State: ABuFfohOVRxoOLyfqWLxWB4vmWAYOvBx3Vugq8Ap3ofgfpZtXSTnIyEN dxBOcsWzejqEvoF0CLbuxrQ= X-Google-Smtp-Source: ACcGV60XS8JFxkYCpCjUp1extw8A1BUDnNAUW+2CM81iKr9uV8mZ/hQH5NfqTow8kPiDXfNXEWY9oA== X-Received: by 2002:a63:e70a:: with SMTP id b10-v6mr27348265pgi.363.1539145999431; Tue, 09 Oct 2018 21:33:19 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id n63-v6sm21171025pfn.9.2018.10.09.21.33.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Oct 2018 21:33:18 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, corbet@lwn.net, linux-doc@vger.kernel.org Subject: [PATCH 2/2] hwmon: (ina3221) Add operating mode support Date: Tue, 9 Oct 2018 21:33:10 -0700 Message-Id: <20181010043310.30873-3-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181010043310.30873-1-nicoleotsuka@gmail.com> References: <20181010043310.30873-1-nicoleotsuka@gmail.com> Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The hwmon core now has a new optional mode interface. So this patch just implements this mode support so that user space can check and configure via sysfs node its operating modes: power-down, one-shot, and continuous modes. Signed-off-by: Nicolin Chen --- drivers/hwmon/ina3221.c | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index d61688f04594..5218fd85506d 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -77,6 +77,28 @@ enum ina3221_channels { INA3221_NUM_CHANNELS }; +enum ina3221_modes { + INA3221_MODE_POWERDOWN, + INA3221_MODE_ONESHOT, + INA3221_MODE_CONTINUOUS, + INA3221_NUM_MODES, +}; + +static const char *ina3221_mode_names[INA3221_NUM_MODES] = { + [INA3221_MODE_POWERDOWN] = "power-down", + [INA3221_MODE_ONESHOT] = "one-shot", + [INA3221_MODE_CONTINUOUS] = "continuous", +}; + +static const u16 ina3221_mode_val[] = { + [INA3221_MODE_POWERDOWN] = INA3221_CONFIG_MODE_POWERDOWN, + [INA3221_MODE_ONESHOT] = INA3221_CONFIG_MODE_SHUNT | + INA3221_CONFIG_MODE_BUS, + [INA3221_MODE_CONTINUOUS] = INA3221_CONFIG_MODE_CONTINUOUS | + INA3221_CONFIG_MODE_SHUNT | + INA3221_CONFIG_MODE_BUS, +}; + /** * struct ina3221_input - channel input source specific information * @label: label of channel input source @@ -386,9 +408,51 @@ static const struct hwmon_ops ina3221_hwmon_ops = { .write = ina3221_write, }; +static int ina3221_mode_get_index(struct device *dev, unsigned int *index) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + u16 mode = ina->reg_config & INA3221_CONFIG_MODE_MASK; + + if (mode == INA3221_CONFIG_MODE_POWERDOWN) + *index = INA3221_MODE_POWERDOWN; + if (mode & INA3221_CONFIG_MODE_CONTINUOUS) + *index = INA3221_MODE_CONTINUOUS; + else + *index = INA3221_MODE_ONESHOT; + + return 0; +} + +static int ina3221_mode_set_index(struct device *dev, unsigned int index) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, + INA3221_CONFIG_MODE_MASK, + ina3221_mode_val[index]); + if (ret) + return ret; + + /* Cache the latest config register value */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + return 0; +} + +static const struct hwmon_mode ina3221_hwmon_mode = { + .names = ina3221_mode_names, + .list_size = INA3221_NUM_MODES, + .get_index = ina3221_mode_get_index, + .set_index = ina3221_mode_set_index, +}; + static const struct hwmon_chip_info ina3221_chip_info = { .ops = &ina3221_hwmon_ops, .info = ina3221_info, + .mode = &ina3221_hwmon_mode, }; /* Extra attribute groups */