From patchwork Thu Oct 25 23:51:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10656823 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 9286F14E2 for ; Thu, 25 Oct 2018 23:51:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 87FE72C162 for ; Thu, 25 Oct 2018 23:51:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7C2362C1EC; Thu, 25 Oct 2018 23:51:53 +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 113422C162 for ; Thu, 25 Oct 2018 23:51:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727660AbeJZI0M (ORCPT ); Fri, 26 Oct 2018 04:26:12 -0400 Received: from mail-pg1-f196.google.com ([209.85.215.196]:44508 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727567AbeJZI0K (ORCPT ); Fri, 26 Oct 2018 04:26:10 -0400 Received: by mail-pg1-f196.google.com with SMTP id w3-v6so4753087pgs.11; Thu, 25 Oct 2018 16:51:30 -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=iq4W3ckbo3T05M9TEh43hdkecT0tn3SQVt0ZFCy+G8o=; b=NjD4MyuhkPIOTPElvaykqmidngfdHDf6mo8KuUo+K7KTG/FTm8TWaa3Gk5A+LsNT3q WC+LVh44Ti6vay+gHsBre6CuQGvIKoj+AQps6qeM4B4CBLdV+kNggveUHPL3E0jn+8Z/ UILuYyUlOjoozYGTZ4Ie9VS9ycOpYisNaQB/VuvllyDD8luLCzarhg+VwMFjTBQBfIFV XIzvipZAybzuDbZ41uCX7Cr83HiRaAo6Qe6jVufo+VdKitcz8gyPJtsngernN4XqWY11 Jhwm74ard0bJ9xuKgB7Te6LDXyaEM5YVk/IVGMg17J3PgEE2n4I+++YYtyGaQkw5FQ0w fujw== 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=iq4W3ckbo3T05M9TEh43hdkecT0tn3SQVt0ZFCy+G8o=; b=ELsvyw8Nvn/gcqFUoGs8eE133hMCFYwgy3p8J4vwXpgVeWJviAlzq62gQAP45iFtrI x4O+PjrqiFnhkDSFGZ9Og9oxRhLjd7sgWmrV6m2+71opmc+mWnYWL7xrcM4Dx6fZ/xyB YBVJIAyE3ib8tQ5Sp/TSAYmRgueD92tSy3G3AJzV/+HFBqRF8w3r8AXUrd/4e3B8mGId M/9N795ykaJtz7Dr7Gm04J6DZLCvzPYVRuyAvpTsoKHXg1x9LGxVAX0AANHXvQhfjC4P gR0Br7gxIHPy/dbNnT5ffprlzKpxCiANImMD99aHBlAnndAGgTkAb8jds3lEIWP+OOMo mRSg== X-Gm-Message-State: AGRZ1gIOyU9+GF0JIzHmVeprFgPEWtA6t2sVby08xl4gwYP/M0UtvFVG sDjebhWRSMdbySmWKr7OmX0= X-Google-Smtp-Source: AJdET5dTxr2Pkt5+HK7oJD7bOCic5UrSa1A6+/hajnYMCnmOW68+yDkjNKMft74e5qDuw0L3yABgcw== X-Received: by 2002:a63:d0e:: with SMTP id c14-v6mr1147205pgl.281.1540511489426; Thu, 25 Oct 2018 16:51:29 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id e189-v6sm10453806pfa.91.2018.10.25.16.51.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Oct 2018 16:51:28 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 1/5] hwmon: (core) Add pm ops to hwmon class Date: Thu, 25 Oct 2018 16:51:18 -0700 Message-Id: <20181025235122.3240-2-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025235122.3240-1-nicoleotsuka@gmail.com> References: <20181025235122.3240-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 generates an extra child dev pointer for every registered hwmon driver so as to link the new device to hwmon class, and it exposes this new dev in /sys/class/hwmon/hwmon*/ directory including a power directory for pm runtime. However, there is currently no way for hwmon drivers to link their own pm related information to this power directory, so it's always showing unsupported even if the driver implements the pm ops. This is because pm_runtime core scans PM runtime callbacks in the dev->driver pointer while this new child dev doesn't have a driver pointer. It sounds easier to merely copy this driver pointer from the parent dev to the child dev, however, this'd create some problem like the same suspend() function might be called twice during system suspend cycle and the second call may fail since the device is already suspended, so the driver would have to work around to bypass one of the two callbacks. Actually, pm_runtime core also scans a class-level pm pointer: else if (dev->class && dev->class->pm) ops = dev->class->pm; This means that hwmon class in the hwmon core could actually have its own generic pm callbacks so that a registered driver would have the capability to link their own callbacks to the hwmon core's. So this patch adds a pm pointer to the hwmon class with some generic pm callbacks of system suspend/resume and pm_runtime suspend/resume, and also allows hwmon drivers to pass valid pm pointers through _with_info API when registering devices. Signed-off-by: Nicolin Chen --- Changelog v3->v4: * Dropped the risky pointer copies * Added generic pm runtime callbacks to the hwmon class v2->v3: * N/A v1->v2: * Added device pointers drivers/hwmon/hwmon.c | 24 ++++++++++++++++++++++++ include/linux/hwmon.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 975c95169884..10bbd36be4a5 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -103,11 +104,34 @@ static void hwmon_dev_release(struct device *dev) kfree(to_hwmon_device(dev)); } +#define HWMON_PM_FUNCTION(name) \ +static int __maybe_unused hwmon_##name(struct device *dev) \ +{ \ + struct hwmon_device *hwdev = to_hwmon_device(dev); \ + const struct hwmon_chip_info *chip = hwdev->chip; \ + \ + if (chip && chip->pm && chip->pm->name) \ + return chip->pm->name(dev); \ + \ + return 0; \ +} + +HWMON_PM_FUNCTION(suspend) +HWMON_PM_FUNCTION(resume) +HWMON_PM_FUNCTION(runtime_suspend) +HWMON_PM_FUNCTION(runtime_resume) + +static const struct dev_pm_ops hwmon_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hwmon_suspend, hwmon_resume) + SET_RUNTIME_PM_OPS(hwmon_runtime_suspend, hwmon_runtime_resume, NULL) +}; + static struct class hwmon_class = { .name = "hwmon", .owner = THIS_MODULE, .dev_groups = hwmon_dev_attr_groups, .dev_release = hwmon_dev_release, + .pm = &hwmon_pm, }; static DEFINE_IDA(hwmon_ida); diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 99e0c1b0b5fb..edbeddb489f8 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -369,10 +369,12 @@ struct hwmon_channel_info { * Chip configuration * @ops: Pointer to hwmon operations. * @info: Null-terminated list of channel information. + * @pm: Pointer to dev_pm_ops callbacks. */ struct hwmon_chip_info { const struct hwmon_ops *ops; const struct hwmon_channel_info **info; + const struct dev_pm_ops *pm; }; /* hwmon_device_register() is deprecated */ From patchwork Thu Oct 25 23:51:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10656825 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 24C3314E2 for ; Thu, 25 Oct 2018 23:52:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1960A2C162 for ; Thu, 25 Oct 2018 23:52:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0DDBB2C1EC; Thu, 25 Oct 2018 23:52:02 +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 4427C2C162 for ; Thu, 25 Oct 2018 23:51:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727613AbeJZI0d (ORCPT ); Fri, 26 Oct 2018 04:26:33 -0400 Received: from mail-pf1-f195.google.com ([209.85.210.195]:39606 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727655AbeJZI0L (ORCPT ); Fri, 26 Oct 2018 04:26:11 -0400 Received: by mail-pf1-f195.google.com with SMTP id c25-v6so4975807pfe.6; Thu, 25 Oct 2018 16:51:30 -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=jgCJL9czCPigEGOwpf3mxraCR5nZbEWiDU5Zl8DZfBo=; b=hP0yucY8ktiFpTgPsYLtrVtWoSfujMUYYeN24w/XBfFv40TeUsQlQ7YlDqGnxP/c17 uL9CU5nc6gkV9m6gZE5xVGqEIAbzoKUY0d819ZuOU33dyREENZdN6MRqUNbrAKBm3Abs /5/OJnyL1MYfxoVo1fqwx33YcL5ZeZRQjZ5Oeq4Ayk8SLNksYZVXQ4hbrBeMLv7zQKQu JINz+riFoIfIGeGNQOQLvdPrbEWXZTIxUVoX0EtGVOXaMsY+UMv6C7aekosli8+iYhP7 kWILHdF75Yo/SRQnGngKPEpS5D/1FKfAU2WTNsQ5xSWZHz/47DVaeXNaO2OYRvpLRprH 04Fg== 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=jgCJL9czCPigEGOwpf3mxraCR5nZbEWiDU5Zl8DZfBo=; b=bKgZyjGIaLez+HY9W0bOtMCMK9S2qoXst616uxjKsgOafGEAZA7H0XMcBXVAP+Obyh 89dJImREbaeC63vQAPo1FUb6wnU/uNQtRNaypU3uBVjA0xmZulRBS9dkz79H6EKiM15t mQj1WLyTnLrOCwvd17O1VIAqBgZg+EI7er0d80J8tzmd6DpljxNxw0jXMJ5Zrrr/IPC7 1VobZZO21uG3JP9vQZ6IeTVrvVvyvMuD1xKA3C9k7EQzvwQzzaSHg/LXfiVn6MyVznOT NBNLY5zjgpfAWaMV9OVZHtrV/HmPEXzm+JWrYXTp5tvOmN/5nBHyN6SeE0HypK0c8n3t saAQ== X-Gm-Message-State: AGRZ1gL90GQGS5AM6J5YAGqrMJJDuuWjpk82FHaddi694c/zTKVflpd4 LMRiBHL1aHWMQfD6nz7DVL4= X-Google-Smtp-Source: AJdET5eLArg8BESAK6AKnHF1kbvpB6HjRmUC7EhAzZzpdCx+UxAo4ycCCr7qWvIoazEdMYOhq1T4LA== X-Received: by 2002:a63:1765:: with SMTP id 37-v6mr1183883pgx.131.1540511490149; Thu, 25 Oct 2018 16:51:30 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id e189-v6sm10453806pfa.91.2018.10.25.16.51.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Oct 2018 16:51:29 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 2/5] hwmon: (ina3221) Check channel status for alarms attribute read Date: Thu, 25 Oct 2018 16:51:19 -0700 Message-Id: <20181025235122.3240-3-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025235122.3240-1-nicoleotsuka@gmail.com> References: <20181025235122.3240-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 is nothing critically wrong to read these two attributes without having a is_enabled() check at this point. But reading the MASK_ENABLE register would clear the CVRF bit according to the datasheet. So it'd be safer to fence for disabled channels in order to add pm runtime feature. Signed-off-by: Nicolin Chen --- Changelog v2->v4: * N/A v1->v2: * Returned 0 for alert flags instead of -ENODATA drivers/hwmon/ina3221.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index d61688f04594..26cdf3342d80 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -200,6 +200,12 @@ static int ina3221_read_curr(struct device *dev, u32 attr, return 0; case hwmon_curr_crit_alarm: case hwmon_curr_max_alarm: + /* No actual register read if channel is disabled */ + if (!ina3221_is_enabled(ina, channel)) { + /* Return 0 for alert flags */ + *val = 0; + return 0; + } ret = regmap_field_read(ina->fields[reg], ®val); if (ret) return ret; From patchwork Thu Oct 25 23:51:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10656819 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 63C7F13A9 for ; Thu, 25 Oct 2018 23:51:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 596942C162 for ; Thu, 25 Oct 2018 23:51:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4D7952C1EC; Thu, 25 Oct 2018 23:51:46 +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 CA3432C162 for ; Thu, 25 Oct 2018 23:51:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727707AbeJZI0O (ORCPT ); Fri, 26 Oct 2018 04:26:14 -0400 Received: from mail-pg1-f195.google.com ([209.85.215.195]:45785 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727658AbeJZI0N (ORCPT ); Fri, 26 Oct 2018 04:26:13 -0400 Received: by mail-pg1-f195.google.com with SMTP id s3-v6so4749661pga.12; Thu, 25 Oct 2018 16:51:32 -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=WhIVuvKjVd2x3Svm7Qnl0DY6kw49Vyz/j7HQ4NEdOMI=; b=H/pYhpkXfPKX5PM68KnHszps0OkiRmEqrKDvPeAOPjWOm2TZc0BGB3fma9GkJFGKo4 FOHO/o0FIanSZZs8g2oYojQICfbSvH43GSIj1GeyvuEhT6lVxYz2qigDE+CrKYhHy15z EuN3FPESM39GLp08qB/2soJNznz4k/IldbeBf89NSXaEnCH9VbeQQmD4x9XHy/xiZPsh tRI1ACRA2WQBi0j2wxQ2pmOHQUAD481LOPasuJooyagZx1g3FNUZGhNubuPDQlilYg8A 5K82K8L4e5+BY7jGS5en4uov2hNssoLOQTsCwTVCRR21jOdiAEzBBRAlPt1hTWW0rfsa shsQ== 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=WhIVuvKjVd2x3Svm7Qnl0DY6kw49Vyz/j7HQ4NEdOMI=; b=AuxNDijgRTswWLciP0svgz7dW0E8aRl3ms+GnPJCAE1/NnT5N6ROsIYtRpcPtjg3wN aaWYMCYEsGzwdtuHQyyrhhKChPwQ/j5aVZ7Go1UD62y9aWhB+L6RTrzVmj7cirLZPjLl g3XG57D2UEblOoKM9ihwPai6OPkqrs3vikXRIl0/eaAg6gp345ltS29Gsopym5i+F79Y hHdK19wko4EdQh3X3S8L5msfJcyoPnYYGkmT6wnW/I9z6+5UTrH2PFLjH2gSyHGxMfxG +tkqawMvjCLbqFGGiOwBIetaP0BzuzCVhgb7EI3mihfqD0x3GnEeoXl7v5+9ckrtW/ZF lzXw== X-Gm-Message-State: AGRZ1gKeHhJ34zmKB/s8mqZ9thCuU0yOfn9ZKeS0KjlYdcvxgyh8t5k9 dN6zBpwUEYsv/j5OAGc7EVL4vfhc X-Google-Smtp-Source: AJdET5fneIBKaQ+ZPci9npuxx5t+ki0xWyFaG6PBKg0x3iZFsvXs3SkZuO1L1B5lkuRR9ZPgSxcOOw== X-Received: by 2002:a63:2903:: with SMTP id p3-v6mr1187078pgp.188.1540511491263; Thu, 25 Oct 2018 16:51:31 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id e189-v6sm10453806pfa.91.2018.10.25.16.51.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Oct 2018 16:51:30 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 3/5] hwmon: (ina3221) Serialize sysfs ABI accesses Date: Thu, 25 Oct 2018 16:51:20 -0700 Message-Id: <20181025235122.3240-4-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025235122.3240-1-nicoleotsuka@gmail.com> References: <20181025235122.3240-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 This change adds a mutex to serialize accesses of sysfs attributes. This is required when polling CVRF bit of the MASK/ENABLE register because this bit is cleared on a read of this MASK/ENABLE register or a write to CONFIG register, which means that this bit might be accidentally cleared by reading other fields like alert flags. So this patch adds a mutex lock to protect the write() and read() callbacks. The read_string() callback won't need the lock since it just returns the label without touching any hardware register. Signed-off-by: Nicolin Chen --- Changlog v1->v4: * N/A drivers/hwmon/ina3221.c | 51 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 26cdf3342d80..10e8347a3c80 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -94,12 +95,14 @@ struct ina3221_input { * @regmap: Register map of the device * @fields: Register fields of the device * @inputs: Array of channel input source specific structures + * @lock: mutex lock to serialize sysfs attribute accesses * @reg_config: Register value of INA3221_CONFIG */ struct ina3221_data { struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS]; + struct mutex lock; u32 reg_config; }; @@ -265,29 +268,53 @@ static int ina3221_write_enable(struct device *dev, int channel, bool enable) static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + switch (type) { case hwmon_in: /* 0-align channel ID */ - return ina3221_read_in(dev, attr, channel - 1, val); + ret = ina3221_read_in(dev, attr, channel - 1, val); + break; case hwmon_curr: - return ina3221_read_curr(dev, attr, channel, val); + ret = ina3221_read_curr(dev, attr, channel, val); + break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + break; } + + mutex_unlock(&ina->lock); + + return ret; } static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + mutex_lock(&ina->lock); + switch (type) { case hwmon_in: /* 0-align channel ID */ - return ina3221_write_enable(dev, channel - 1, val); + ret = ina3221_write_enable(dev, channel - 1, val); + break; case hwmon_curr: - return ina3221_write_curr(dev, attr, channel, val); + ret = ina3221_write_curr(dev, attr, channel, val); + break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + break; } + + mutex_unlock(&ina->lock); + + return ret; } static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type, @@ -582,6 +609,7 @@ static int ina3221_probe(struct i2c_client *client, if (ret) return ret; + mutex_init(&ina->lock); dev_set_drvdata(dev, ina); hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, @@ -589,12 +617,22 @@ static int ina3221_probe(struct i2c_client *client, ina3221_groups); if (IS_ERR(hwmon_dev)) { dev_err(dev, "Unable to register hwmon device\n"); + mutex_destroy(&ina->lock); return PTR_ERR(hwmon_dev); } return 0; } +static int ina3221_remove(struct i2c_client *client) +{ + struct ina3221_data *ina = dev_get_drvdata(&client->dev); + + mutex_destroy(&ina->lock); + + return 0; +} + static int __maybe_unused ina3221_suspend(struct device *dev) { struct ina3221_data *ina = dev_get_drvdata(dev); @@ -663,6 +701,7 @@ MODULE_DEVICE_TABLE(i2c, ina3221_ids); static struct i2c_driver ina3221_i2c_driver = { .probe = ina3221_probe, + .remove = ina3221_remove, .driver = { .name = INA3221_DRIVER_NAME, .of_match_table = ina3221_of_match_table, From patchwork Thu Oct 25 23:51:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10656821 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 C823513A9 for ; Thu, 25 Oct 2018 23:51:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BBD242C162 for ; Thu, 25 Oct 2018 23:51:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ABDED2C1EC; Thu, 25 Oct 2018 23:51:50 +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 2EE5B2C162 for ; Thu, 25 Oct 2018 23:51:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727690AbeJZI0O (ORCPT ); Fri, 26 Oct 2018 04:26:14 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:38999 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727567AbeJZI0N (ORCPT ); Fri, 26 Oct 2018 04:26:13 -0400 Received: by mail-pl1-f195.google.com with SMTP id e67-v6so4594338plb.6; Thu, 25 Oct 2018 16:51:32 -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=kUDLRUfzNbTxD5o9nhpVHypSp7vSjORMAQfEIdztF4M=; b=HIgjX48JO/1ruRGRKiUzG5Z9JoZwa+ONCLhPtaA0N0rL5i+qyTBcCS+ZvCKCrXdptl 53eVi7osMFU89zhRDGZ0DdLGGhmWzEFnKKUawVcB+bpZQCZHCbUaFfpcoziGDmZxmE0y SkvgTY8jmSJjpJd76R5Cgx8W1ueTSjiapykKJTrAzbPIWUUmckoyH4TK+l5GFRZL87ay LQDDTePEzAKc4k0xqJ3eBP0ra29Zo6H2D2qhraXGM/XsgpUblKvcsg5yIQp4M4dz0PYg bs/QNk8bz9XQioSEx8Gw1EoK9DfLlHGFDCNlFLHxxdgUN0x64UdQi2uUfvso3hKF/cH7 Qreg== 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=kUDLRUfzNbTxD5o9nhpVHypSp7vSjORMAQfEIdztF4M=; b=e23NM7KfDbpTYaQ3u6g7nysL4ziBTM4Ybgj71VaV5cSt97Rb6KKxhsrsjznguF/tN8 8Otl84+JSOlXVt81BQ+HR+n23IW8Gdw/edWvSt3NM99spSUl5uoWt572b8Igd6iCqlHG 0r+ZV+QzdNN5uHOOjden3NbW3vc7WMa6DSiOSiwBy19FFIb5Ln7zsi8+aO05lpcTth+A t49Rl52bzm6NJv2U/du73LDGxz5g8YloeViZiHb77t0JEPtejZugq1oYNlbqPG57v/ab vJWvUAphN7W8P/BVZAw8Gja8wH/KwEV+aaJCzDG/kgGHEOvz1I+2mH2RyHZTddf9N2cK Er/A== X-Gm-Message-State: AGRZ1gIiJnZGbI++/lTqeRgFg/NmDBf8xr92qU6mZ28m9Wekqn+in+NU OWzNJaZprhE4ijMs30uje0hYqxrb X-Google-Smtp-Source: AJdET5cVeL/yTe2GhBUnewpnOeEIAtN5LRlQNe/09Nvf35SimyiR/1vM3ZP1XJ2K3yn4ZHyLYHjyNQ== X-Received: by 2002:a17:902:e185:: with SMTP id cd5-v6mr1155116plb.224.1540511492122; Thu, 25 Oct 2018 16:51:32 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id e189-v6sm10453806pfa.91.2018.10.25.16.51.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Oct 2018 16:51:31 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 4/5] hwmon: (ina3221) Make sure data is ready before reading Date: Thu, 25 Oct 2018 16:51:21 -0700 Message-Id: <20181025235122.3240-5-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025235122.3240-1-nicoleotsuka@gmail.com> References: <20181025235122.3240-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 data might need some time to get ready after channel enabling, although the data register is always readable. The CVRF bit is to indicate that data conversion is finished, so polling the CVRF bit before data reading could ensure the result being valid. An alternative way could be to wait for expected time between the channel enabling and the data reading. And this could avoid extra I2C communications. However, INA3221 seemly takes longer time than what's stated in the datasheet. Test results show that sometimes it couldn't finish data conversion in time. So this patch plays safe by adding a CVRF polling to make sure the data register is updated with the new data. Signed-off-by: Nicolin Chen --- Changelog v3->v4: * N/A v2->v3: * Dropped timeout dev_err messages as it's indicated in the errno v1->v2: * Moved CVRF polling to data read routine * Added calculation of wait time based on conversion time setting drivers/hwmon/ina3221.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 10e8347a3c80..07dd6ef58d3e 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -44,6 +44,13 @@ #define INA3221_CONFIG_MODE_SHUNT BIT(0) #define INA3221_CONFIG_MODE_BUS BIT(1) #define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) +#define INA3221_CONFIG_VSH_CT_SHIFT 3 +#define INA3221_CONFIG_VSH_CT_MASK GENMASK(5, 3) +#define INA3221_CONFIG_VSH_CT(x) (((x) & GENMASK(5, 3)) >> 3) +#define INA3221_CONFIG_VBUS_CT_SHIFT 6 +#define INA3221_CONFIG_VBUS_CT_MASK GENMASK(8, 6) +#define INA3221_CONFIG_VBUS_CT(x) (((x) & GENMASK(8, 6)) >> 6) +#define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) #define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) #define INA3221_RSHUNT_DEFAULT 10000 @@ -52,6 +59,9 @@ enum ina3221_fields { /* Configuration */ F_RST, + /* Status Flags */ + F_CVRF, + /* Alert Flags */ F_WF3, F_WF2, F_WF1, F_CF3, F_CF2, F_CF1, @@ -63,6 +73,7 @@ enum ina3221_fields { static const struct reg_field ina3221_reg_fields[] = { [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), + [F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0), [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), @@ -111,6 +122,28 @@ static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) return ina->reg_config & INA3221_CONFIG_CHx_EN(channel); } +/* Lookup table for Bus and Shunt conversion times in usec */ +static const u16 ina3221_conv_time[] = { + 140, 204, 332, 588, 1100, 2116, 4156, 8244, +}; + +static inline int ina3221_wait_for_data(struct ina3221_data *ina) +{ + u32 channels = hweight16(ina->reg_config & INA3221_CONFIG_CHs_EN_MASK); + u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(ina->reg_config); + u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(ina->reg_config); + u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; + u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; + u32 wait, cvrf; + + /* Calculate total conversion time */ + wait = channels * (vbus_ct + vsh_ct); + + /* Polling the CVRF bit to make sure read data is ready */ + return regmap_field_read_poll_timeout(ina->fields[F_CVRF], + cvrf, cvrf, wait, 100000); +} + static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, int *val) { @@ -150,6 +183,10 @@ static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val) if (!ina3221_is_enabled(ina, channel)) return -ENODATA; + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + ret = ina3221_read_value(ina, reg, ®val); if (ret) return ret; @@ -189,6 +226,11 @@ static int ina3221_read_curr(struct device *dev, u32 attr, case hwmon_curr_input: if (!ina3221_is_enabled(ina, channel)) return -ENODATA; + + ret = ina3221_wait_for_data(ina); + if (ret) + return ret; + /* fall through */ case hwmon_curr_crit: case hwmon_curr_max: From patchwork Thu Oct 25 23:51:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10656817 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 A280514E2 for ; Thu, 25 Oct 2018 23:51:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 965E12C162 for ; Thu, 25 Oct 2018 23:51:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8A7F22C1EC; Thu, 25 Oct 2018 23:51:41 +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 B61DB2C162 for ; Thu, 25 Oct 2018 23:51:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727734AbeJZI0P (ORCPT ); Fri, 26 Oct 2018 04:26:15 -0400 Received: from mail-pl1-f196.google.com ([209.85.214.196]:36126 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727687AbeJZI0O (ORCPT ); Fri, 26 Oct 2018 04:26:14 -0400 Received: by mail-pl1-f196.google.com with SMTP id y11-v6so4606939plt.3; Thu, 25 Oct 2018 16:51:33 -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=UyittIA2+cQ6D8Jn5aD66oLNq1HwhWgYhYoAUPPQ5VE=; b=i5T4zDMCig0zFGsob1uaV42lnC8xvPWvRqqFk2xZufhsEKM0q975KUOc1LNo4T2EKn RulrW5bSsrMSEHC/Mx78AI5sX4AeTn2MgEbZGShp/xE6DovpHDh0T6OhNEDpAnJOvhSO CdPML3Jw4oezMi7BJ5tMuDTVD3sDSbWOwJPvQfy9LzZwnWzGqpG3oQ2MIoA3fKAwcHQ7 JJdLkS3D4ufbs3PDlTQPIO9ks44Aua38XlQBBZqEbZBMLpKg0Zxsb4SQ26uNShWqXiO2 PgRjGR1T0VlxzXKefPmkIFv/j7ruVvLqWDc0qVTk+Zbl0Zn6r0f/lMzg4j+BmhmIyTnf 7Whw== 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=UyittIA2+cQ6D8Jn5aD66oLNq1HwhWgYhYoAUPPQ5VE=; b=jc5AmqWmf2pGgqEa2rIi/YAHfw2o6wNIOaDVAFZf1kMqTYBSllRij+U4f8aTs/kCyi 6GDt6OweOjsnrlj4OOhho3KjCNnOhwAQcHba0ajYuvzlcz10snzwRxAHN4g2aBKPfol1 UZcI927lo/ah214sRk0q+cVf9gf4Kuq1HIh9dxVJDwAQZHvTwxttCq34QCpDFeGVE1V8 LciWAhPZ/8VLamDJiN4CIuBWmvkEX3p/EnxRO9b/dXcCILp86B8dJQvR4hTi8mCMedDZ O6UCg4iMiO9zugThxm/1ZUagB93qaXjRZCzihMmLoHSVtUusMqoeYF1vrw3e4ZCXDwEK oK0A== X-Gm-Message-State: AGRZ1gJR4EuN5yw5cTQjOPRYbufT+NlqR5JGtjvEdavD9pZs1U8y7CYh Z2T6r4L0NtM93Xv09xw7Kvs= X-Google-Smtp-Source: AJdET5fhGHGyri8tPLOA7B1vO9yszowkPng3Jpnx5Ta+xIwONu4tn8ZZU/sjjlpPQGnOjxasnMjnLQ== X-Received: by 2002:a17:902:3064:: with SMTP id u91-v6mr1169126plb.176.1540511493154; Thu, 25 Oct 2018 16:51:33 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id e189-v6sm10453806pfa.91.2018.10.25.16.51.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Oct 2018 16:51:32 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 5/5] hwmon: (ina3221) Add PM runtime support Date: Thu, 25 Oct 2018 16:51:22 -0700 Message-Id: <20181025235122.3240-6-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025235122.3240-1-nicoleotsuka@gmail.com> References: <20181025235122.3240-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 If all three channels are disabled via in[123]_enable ABI, the driver could suspend the chip for power saving purpose. So this patch adds the PM runtime support in order to gain more power control than system suspend and resume use case. For PM runtime, there are a few related changes happening: 1) Added a new explicit hdev device pointer for all the PM runtime callbacks. This is because hwmon core registers a child device for each hwmon driver. So there might be a mismatch between two device pointers in the driver if mixing using them. 2) Passed the pm pointer via _with_info API to hwmon core so as to let the hwmon class control those callbacks. 3) Added a check in ina3221_is_enabled() to make sure that the chip is resumed. 4) Bypassed the unchanged status in ina3221_write_enable() in order to keep the PM runtime refcount being matched. 5) Removed the reset routine in the probe() by calling the resume() via pm_runtime_get_sync() instead, as they're similar. It's also necessary to do so to match initial PM refcount with the number of enabled channels. Signed-off-by: Nicolin Chen --- Changelog v3->v4: * Passed pm pointer via _with_info API instead the i2c driver v2->v3: * Improved a dev_err message * Added comments at pm_runtime_put_noidle() callbacks * Added pm_runtime header file in an alphabetical order v1->v2: * Bypassed i2c_client->dev in suspend/resume() * Added a missing '\n' in one dev_err() drivers/hwmon/ina3221.c | 213 ++++++++++++++++++++++++++-------------- 1 file changed, 137 insertions(+), 76 deletions(-) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 07dd6ef58d3e..974a29b1c8f0 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define INA3221_DRIVER_NAME "ina3221" @@ -53,6 +54,7 @@ #define INA3221_CONFIG_CHs_EN_MASK GENMASK(14, 12) #define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) +#define INA3221_CONFIG_DEFAULT 0x7127 #define INA3221_RSHUNT_DEFAULT 10000 enum ina3221_fields { @@ -103,6 +105,7 @@ struct ina3221_input { /** * struct ina3221_data - device specific information + * @hdev: Device pointer of hwmon child device, used for pm runtime * @regmap: Register map of the device * @fields: Register fields of the device * @inputs: Array of channel input source specific structures @@ -110,6 +113,7 @@ struct ina3221_input { * @reg_config: Register value of INA3221_CONFIG */ struct ina3221_data { + struct device *hdev; struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS]; @@ -119,7 +123,8 @@ struct ina3221_data { static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) { - return ina->reg_config & INA3221_CONFIG_CHx_EN(channel); + return pm_runtime_active(ina->hdev) && + (ina->reg_config & INA3221_CONFIG_CHx_EN(channel)); } /* Lookup table for Bus and Shunt conversion times in usec */ @@ -290,21 +295,48 @@ static int ina3221_write_enable(struct device *dev, int channel, bool enable) { struct ina3221_data *ina = dev_get_drvdata(dev); u16 config, mask = INA3221_CONFIG_CHx_EN(channel); + u16 config_old = ina->reg_config & mask; int ret; config = enable ? mask : 0; + /* Bypass if enable status is not being changed */ + if (config_old == config) + return 0; + + /* For enabling routine, increase refcount and resume() at first */ + if (enable) { + ret = pm_runtime_get_sync(ina->hdev); + if (ret < 0) { + dev_err(dev, "Failed to get PM runtime\n"); + return ret; + } + } + /* Enable or disable the channel */ ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); if (ret) - return ret; + goto fail; /* Cache the latest config register value */ ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); if (ret) - return ret; + goto fail; + + /* For disabling routine, decrease refcount or suspend() at last */ + if (!enable) + pm_runtime_put_sync(ina->hdev); return 0; + +fail: + if (enable) { + dev_err(dev, "Failed to enable channel %d: error %d\n", + channel, ret); + pm_runtime_put_sync(ina->hdev); + } + + return ret; } static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, @@ -461,9 +493,66 @@ static const struct hwmon_ops ina3221_hwmon_ops = { .write = ina3221_write, }; +static int __maybe_unused ina3221_suspend(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + /* Save config register value and enable cache-only */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); + if (ret) + return ret; + + /* Set to power-down mode for power saving */ + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, + INA3221_CONFIG_MODE_MASK, + INA3221_CONFIG_MODE_POWERDOWN); + if (ret) + return ret; + + regcache_cache_only(ina->regmap, true); + regcache_mark_dirty(ina->regmap); + + return 0; +} + +static int __maybe_unused ina3221_resume(struct device *dev) +{ + struct ina3221_data *ina = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(ina->regmap, false); + + /* Software reset the chip */ + ret = regmap_field_write(ina->fields[F_RST], true); + if (ret) { + dev_err(dev, "Unable to reset device\n"); + return ret; + } + + /* Restore cached register values to hardware */ + ret = regcache_sync(ina->regmap); + if (ret) + return ret; + + /* Restore config register value to hardware */ + ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); + if (ret) + return ret; + + return 0; +} + +static const struct dev_pm_ops ina3221_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ina3221_suspend, ina3221_resume, NULL) +}; + static const struct hwmon_chip_info ina3221_chip_info = { .ops = &ina3221_hwmon_ops, .info = ina3221_info, + .pm = &ina3221_pm, }; /* Extra attribute groups */ @@ -599,7 +688,6 @@ static int ina3221_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct ina3221_data *ina; - struct device *hwmon_dev; int i, ret; ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); @@ -631,104 +719,78 @@ static int ina3221_probe(struct i2c_client *client, return ret; } - ret = regmap_field_write(ina->fields[F_RST], true); - if (ret) { - dev_err(dev, "Unable to reset device\n"); - return ret; - } - - /* Sync config register after reset */ - ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); - if (ret) - return ret; + /* The driver will be reset, so use reset value */ + ina->reg_config = INA3221_CONFIG_DEFAULT; /* Disable channels if their inputs are disconnected */ for (i = 0; i < INA3221_NUM_CHANNELS; i++) { if (ina->inputs[i].disconnected) ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); } - ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); - if (ret) - return ret; mutex_init(&ina->lock); dev_set_drvdata(dev, ina); - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina, + /* Fence sysfs nodes till pm_runtime is resumed */ + mutex_lock(&ina->lock); + + /* Use the returned hdev for pm_runtime */ + ina->hdev = devm_hwmon_device_register_with_info(dev, client->name, ina, &ina3221_chip_info, ina3221_groups); - if (IS_ERR(hwmon_dev)) { + if (IS_ERR(ina->hdev)) { dev_err(dev, "Unable to register hwmon device\n"); - mutex_destroy(&ina->lock); - return PTR_ERR(hwmon_dev); + ret = PTR_ERR(ina->hdev); + goto fail_lock; } + /* Enable PM runtime -- status is suspended by default */ + pm_runtime_enable(ina->hdev); + + /* Initialize (resume) the device */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + continue; + /* Match the refcount with number of enabled channels */ + ret = pm_runtime_get_sync(ina->hdev); + if (ret < 0) + goto fail_pm; + } + + mutex_unlock(&ina->lock); + return 0; + +fail_pm: + pm_runtime_disable(ina->hdev); + pm_runtime_set_suspended(ina->hdev); + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->hdev); +fail_lock: + mutex_unlock(&ina->lock); + mutex_destroy(&ina->lock); + + return ret; } static int ina3221_remove(struct i2c_client *client) { struct ina3221_data *ina = dev_get_drvdata(&client->dev); + int i; + + pm_runtime_disable(ina->hdev); + pm_runtime_set_suspended(ina->hdev); + + /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + pm_runtime_put_noidle(ina->hdev); mutex_destroy(&ina->lock); return 0; } -static int __maybe_unused ina3221_suspend(struct device *dev) -{ - struct ina3221_data *ina = dev_get_drvdata(dev); - int ret; - - /* Save config register value and enable cache-only */ - ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); - if (ret) - return ret; - - /* Set to power-down mode for power saving */ - ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, - INA3221_CONFIG_MODE_MASK, - INA3221_CONFIG_MODE_POWERDOWN); - if (ret) - return ret; - - regcache_cache_only(ina->regmap, true); - regcache_mark_dirty(ina->regmap); - - return 0; -} - -static int __maybe_unused ina3221_resume(struct device *dev) -{ - struct ina3221_data *ina = dev_get_drvdata(dev); - int ret; - - regcache_cache_only(ina->regmap, false); - - /* Software reset the chip */ - ret = regmap_field_write(ina->fields[F_RST], true); - if (ret) { - dev_err(dev, "Unable to reset device\n"); - return ret; - } - - /* Restore cached register values to hardware */ - ret = regcache_sync(ina->regmap); - if (ret) - return ret; - - /* Restore config register value to hardware */ - ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); - if (ret) - return ret; - - return 0; -} - -static const struct dev_pm_ops ina3221_pm = { - SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume) -}; - static const struct of_device_id ina3221_of_match_table[] = { { .compatible = "ti,ina3221", }, { /* sentinel */ } @@ -747,7 +809,6 @@ static struct i2c_driver ina3221_i2c_driver = { .driver = { .name = INA3221_DRIVER_NAME, .of_match_table = ina3221_of_match_table, - .pm = &ina3221_pm, }, .id_table = ina3221_ids, };