From patchwork Thu Nov 17 12:10:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tom Levens X-Patchwork-Id: 9435395 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E91466047D for ; Thu, 17 Nov 2016 22:45:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D90CB296B5 for ; Thu, 17 Nov 2016 22:45:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CDC3A29705; Thu, 17 Nov 2016 22:45:08 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable 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 227D129702 for ; Thu, 17 Nov 2016 22:45:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752578AbcKQWpB (ORCPT ); Thu, 17 Nov 2016 17:45:01 -0500 Received: from mail-db5eur01on0060.outbound.protection.outlook.com ([104.47.2.60]:35712 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752526AbcKQWo6 (ORCPT ); Thu, 17 Nov 2016 17:44:58 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cern.onmicrosoft.com; s=selector1-cern-ch; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=QcqwIgAYg9vj3tsmqsMPRmdoNf90Jziwt5mZtF/PkXM=; b=BSBA3QfyJJkEcaDTn5COkeuhFdKJ+cR05Bahlir2E02xpU/aJCuixNJ7tdxrUSMpEUqp1eGVUHL/l2hmLZVeydgWogqkdL1w57ZHwTHwx7gDtNC8hvHJKoRZFaSJaGs13efOyLkiSgP5k6nwjL2j0/+fuWHosiIBqpxsRhWBYTg= Received: from HE1PR0601CA0034.eurprd06.prod.outlook.com (10.166.117.44) by VI1PR06MB1680.eurprd06.prod.outlook.com (10.165.236.158) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.734.8; Thu, 17 Nov 2016 12:11:06 +0000 Received: from AM1FFO11FD004.protection.gbl (2a01:111:f400:7e00::184) by HE1PR0601CA0034.outlook.office365.com (2a01:111:e400:c513::44) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.734.8 via Frontend Transport; Thu, 17 Nov 2016 12:11:05 +0000 Authentication-Results: spf=none (sender IP is 188.184.36.16) smtp.mailfrom=mail.cern.ch; vger.kernel.org; dkim=none (message not signed) header.d=none; vger.kernel.org; dmarc=none action=none header.from=cern.ch; Received-SPF: None (protection.outlook.com: mail.cern.ch does not designate permitted sender hosts) Received: from CERNMX14.cern.ch (188.184.36.16) by AM1FFO11FD004.mail.protection.outlook.com (10.174.64.86) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384) id 15.1.721.5 via Frontend Transport; Thu, 17 Nov 2016 12:11:05 +0000 X-IncomingTopHeaderMarker: OriginalChecksum:; UpperCasedChecksum:; SizeAsReceived:1202; Count:15 Received: from pcbe13573-vm.dyndns.cern.ch (128.141.154.157) by cernmxlb4.cern.ch (188.184.36.24) with Microsoft SMTP Server (TLS) id 14.3.319.2; Thu, 17 Nov 2016 13:10:42 +0100 Received: from pcbe13573-vm.dyndns.cern.ch (localhost [127.0.0.1]) by pcbe13573-vm.dyndns.cern.ch (8.14.4/8.14.4) with ESMTP id uAHCAfuv012521; Thu, 17 Nov 2016 13:10:41 +0100 Received: (from tlevens@localhost) by pcbe13573-vm.dyndns.cern.ch (8.14.4/8.14.4/Submit) id uAHCAfQR012520; Thu, 17 Nov 2016 13:10:41 +0100 From: Tom Levens To: CC: , , , , , , Tom Levens Subject: [PATCH v2 3/3] hwmon: ltc2990: support all measurement modes Date: Thu, 17 Nov 2016 13:10:16 +0100 Message-ID: <1479384616-12479-3-git-send-email-tom.levens@cern.ch> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1479384616-12479-1-git-send-email-tom.levens@cern.ch> References: <1479384616-12479-1-git-send-email-tom.levens@cern.ch> MIME-Version: 1.0 X-IncomingHeaderCount: 15 X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:188.184.36.16; IPV:NLI; CTRY:CH; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(428002)(249900001)(199003)(189002)(110136003)(6916009)(92566002)(189998001)(107886002)(1720100001)(36756003)(50986999)(76176999)(4001430100002)(2950100002)(42186005)(6666003)(74482002)(5660300001)(626004)(246002)(47776003)(2351001)(106466001)(7636002)(305945005)(8676002)(356003)(48376002)(7846002)(4326007)(2906002)(50466002)(87936001)(8936002)(86362001)(50226002)(33646002)(5003940100001); DIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR06MB1680; H:CERNMX14.cern.ch; FPR:; SPF:None; PTR:cernmx14.cern.ch; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; AM1FFO11FD004; 1:/LgMRI1JT84vexk1VapL0qTcy+wiUZNKJRY48GB7T5vqEHDsfp/l7lmliev0NAzUrZ6LguStiGovuhGIKG9Y8dPqzzW+LhzRD4W7EkKY8wt4xw+9S2A5WHsCs4+etGR12gMND/cgrpHOqvBoi8v1xFJUm+METH4tp2znk0AlYehzrr0qvNRUo6tv2KBW32xOTcOU7v/1UJGIdCZ28L4+F8b5vQA0xje6enj2Asd/vofxrp6wCrYfGU/8KnO+I3KkAqZBO4NfTtwuZ/3HEblOUSgcYmRXJwbXtO2CKSJk+3cXLnCX5wuEB/GdZD9Ce76EotfuId0b/7VwS5Wv6v3IaYyHnRmP5Wx7bc0m/qs8p5+IwrsL8Az59jKjtLryABLFaMuko7h0cqr+Bhr4cTsY4OhLZIfC0Xey+KMyaQuCkx+hkDh8SNXsMS0Vl2gWuINt0MFCMuGCmiW/KkGmToN17b0XBW4+37kb58GSAfRB19AMimOhNnZR3E4RF5ypmRoCNvK2rYR+bIXbvLQ9p1Taqjgbmc01/LDHOYkKBza2yiQNtYe4H5f4wMujlwJZYr9iB7jz2Ngwb1W+ETBTwNR3bQ== X-Microsoft-Exchange-Diagnostics: 1; VI1PR06MB1680; 2:TZugpFbj5wv7Y4QeU93D+dqndpOusW8j/0qS830HN30IBSkcVj6+NazmxKG4Rik8JLM0P4vppNW+66lw4J5sQLO2xT378dMqDeGOUVGtmtlZRMyOWRGrLQdQfzUzvoE2HbK9UmjIOV1D5kEzLmNkNyi+x9QWc9gbrmHEA9Jrav4=; 3:5mlFKi4xiEOddCb6R7MqWMM/z2oq3lp4v8LBDyyntl2mdbgkbHlJu4/i0TR8lgOrhr9ur9SP6xisKv80lZOtbXntsHgFyAVVBQGValsGpaCE7xoDfxKK2awUJK+/IfkYFOv2Kuk0EozpJEToFz0tgFHBic3fcrPmCWf3PymF3hoze0/x2U3eYNKvEB78geX9KXK0FF8WmRbTtlS6JZ6klh1tDsgkZQOrkGEWw9fuWFN1/9sNbCx25nc0R+X6cghWeZN84CR3odzYwsAWmGzPMQ==; 25:4Up6Stp/MKyRR7XILCfIV35KGm2CLY3ymPDRNTVb3BozfZXRtb1vVdy5PL1kzT2MbfjHcx3pmiEvuCh0OmG1Y7TaMDj7TrnnUfHUK2aUU9HZzL0G2d9S3U8lprcqMbJjYOhTZiteGSUThKu5Hnt0sfvurRRVIG3cx9r3MhdWAg4ik281YhzWbcTSEDJ4RgyZxbT5+dj2S042sWRy7goMpirbsDC3ABAFnYsY2Xpl/jPYSn5YgUM/LVFyZtr6L1AuZKC7GJxrTvp7ut1oyOun5o3x9eevOHWVuHre4/mJvuh1y2MaGyOdMaVv3btQFkj4Wc2u8gK4ilpQj1cdvfeJgQij/2uRAWSBlzMmm1mNACvWAm7sf8k0SJwj5P/42xLBzr24sDMA3fIguvnava7TgCNliNakubURoNewlWIVKj7BKHuV7rQlBcP0jcX9GtMlwxP/OO3zzGC+P2UdhjdCug== X-MS-Office365-Filtering-Correlation-Id: 2794ca9b-8e93-4407-aea3-08d40ee2ce7e X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:VI1PR06MB1680; X-Microsoft-Exchange-Diagnostics: 1; VI1PR06MB1680; 31:/yi8tXpaTvQ2YA8Gpa1Ok+cf/phOyY9/ke1YD4rigURwfio87bLg11GUhEGaKcGkA+BZFDdH+ULCT9JLnK8f3+KQyVN3rKzHETtJ4yLzKFJK1uu7qf2oZ00EejHXdrn64RNoMdD7Tejcuww4Ai9ThggfvCeQzBo7NSk/thsgWlTmrNY9XPqyeZ/LGIzEMyu1SPdIE34OKM5cuBU+gfg2xrj/LSxX/Loeze5HOZ4D0GW9DNww9zPwovYPE4FnFJPk5UUkMDMRTBqKddo5MzpECg==; 20:eliKq2Y3+xbIK8DZG1DgyCpH8FGY+hIWB46FDxtWxmXI2AK76VtTqWcL6eXiUvpRgtAQtzcoggaqlgLfbmmiqmqO3rip3xWV4em2rGphS6F2iMGvy3EzKFdyNGM9Vr20HzwOfFKZebZPGNXRkq+9GojSWQXk+KHpQMiw4NlpzvdHkZV0+SOyalmC44kLNeS3ALdlJ/0SDIUr2Qay0xfSNI4Nxw3TE5fZtuvHHuBX1ruYe1F7C+nE9ZnjvPaGNsA4SmC9Cedu/HycZlvVSvKf3chdYvcmebE+DyiSHbq9uixlc0AAGaFcBeiRBxmhal3Lm8BOAmmY93dn/tO5EULVx+Hl2WWaseuwknEh9ZGbQkkJ52RpHbsSgNMKg7xECqSLH9X5HP0+YmIA0ReDH44CN0tjjA1N0Iwfsw4qn+Vva5Bc8/vum7dNChE/cCFu35580t+SnpAt7oh65XuMRpXsCO1rMSxPYk8/9C9COARQScuwBRA2iTF7hh1iP3CPbcTr X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(20558992708506)(72170088055959)(112613623882745); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040281)(6060326)(601004)(2401047)(13018025)(13016025)(13024025)(13023025)(8121501046)(5005006)(3002001)(10201501046)(6041223)(6061324); SRVR:VI1PR06MB1680; BCL:0; PCL:0; RULEID:; SRVR:VI1PR06MB1680; X-Microsoft-Exchange-Diagnostics: 1; VI1PR06MB1680; 4:tFbyWwPVDY2yhvNOjMTGKLdj3GvL/3yU1vONBGeYM2c9d2WUiSrYmG2mxWv05t5adP+Qmhs/ckribbWF2HdriyyexTscoQchTyOghGn1OFsFNQc8tL73EBISA/W2S1bX6uzP00osOEMpKjmv8gJknFrMweC02D+HbvLD5snrOoGPyXNS4PV1vNBUzG//hUC658dq1CbKXoIIYBNzHNjLHZ9YaiUtkid0/KEvxyQ25XXT7UZjlZXl2RHBWcZlAxREKQ2l5A+G09ztCoY9L1mYb/mcM6e8CulO2Sa2GtY+vk+//z7InD3Yil6eqy9q0j1HDcBIwhOH5Ga6548k6CzlU+k3Q852W9WZp0Z0Hn1uTnsRgTHH2qMynjgMklC+ljEv7D38y6ULCX6qPc2FUHkX5+KY2VRRn+6Yi7ZoduEzzk30CJUPweiIueSdBPuog/g4wBsf3c7wLKnsjwTTymFkpTuQ58G7njYt5b1rIeAvcMXfztRhUGpYSFe1iy84eu5fO5rFMojrGuF9THctc0rfXo1zM0qrdNSllnhu3yBnaZb309sOv1DqtnLodvepstfOc3vkBAfMq26r152JEnm+4BV12h+IN2rPIoe+4Jy+0iesTBObZHhjTK68dazf4jDgZaPiLNr6GTZK3XfLnbDTjw== X-Forefront-PRVS: 01294F875B X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR06MB1680; 23:/DYp4uAHrpFcnGJ6Gk/4Swh2n4+AM71/tzBCrJ/lb?= =?us-ascii?Q?lr62Jp5ZxkaTZwKq4VyHLQyf5EdzharWfLxN5iQAPzsy0qENe9NE3pW9+OLa?= =?us-ascii?Q?rdFSS2PhYILt46IlxPeVb69e8n1sAi75+PTpEAlkYap77yCzpy28/xRT2i/j?= =?us-ascii?Q?w7GZIbS0FRBMxQgtlemHk2JTit7vu/ZiyMTOvRYsjbvT21QZrve0yo1Gohdh?= =?us-ascii?Q?Pz9VFARPfRm+UN91N6HBFOmoI8sxci+TlBNNs/ABGAZirvLI+G4hcrKvflTW?= =?us-ascii?Q?iJh4BDADueaqW9JgKgl9MzgN225H/zZISPpDzrbjYGQ5+1c5trmKW8u63vAO?= =?us-ascii?Q?N9gWNEUZsJRtonnPJ/fPooDELza3NshTKwam+ON0+YGS/243/CLd0OzYUxjL?= =?us-ascii?Q?bE5s2JLw2XC76aAX59tM0BW0ZW9/FohiaCdP6TSm79wnO0s4/vu5Q6Rm5mX2?= =?us-ascii?Q?R+adX8QJPIXmAf5iw5qLwq6GsoUnBNh/K9uyvMRYfE379GCZjf2OuqNdL70m?= =?us-ascii?Q?H8UWHDSkBZwhhIIMqZVc9KARR8aehrHqhVCLS2TqWn9JO23ELt6SS8hQ6Vkh?= =?us-ascii?Q?/965vt9MFUrVHS1IEXSQ+AZJ6q9x117VKWpSAhpijmzjZKyQqkLzRwFtI3vo?= =?us-ascii?Q?JUDja4aEI4Y3V8U2Rm5jGVhVoaoiZrIiLMtc2ye2TdwAm43xd1KoZIBJ7JiE?= =?us-ascii?Q?3ZF7ZmS8TFkKbUKxgAZD3jRVT3Y9Sg//0ZMFqEWW9RIYugThU7IjYozmb6rE?= =?us-ascii?Q?GzQ0kXucuc8VDmZ6mcqVww8SVepOJxb/JFJH2Bd7rWOvlLB8lmBnLiLakeZA?= =?us-ascii?Q?1Ngt+rv9ORxStevO88t6SvT8RxwTe1Ts4FOW3MYwrdfbKX3tYoSMJmTiD7CW?= =?us-ascii?Q?epMGotsLXc1fjN8jZ7vekutCRECsAz3mikg5p5pZFMKJLHmlwKMR+nYOBwJq?= =?us-ascii?Q?wNQkWTb3gvC6jP0z37fPfnd5mgXqSHJWVK+k2nsx98DxzofCWqDnGYfLUfZJ?= =?us-ascii?Q?D4lwhZZXGVXRBQTj+7C/hD68bpi2lGNgyOkhpJluFLUjoJZ3a+rdGtMduoiJ?= =?us-ascii?Q?43Toa8=3D?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR06MB1680; 6:oXTcIMqWscO7Qp+TDmz9JoubqN9rKiPQhcAYKZ4VgaNfJkiKCLH5VKQZwhINsOIjkqbhZoquuuhf3dKz147Yn83mQnEcmmmaGi71jhLOs5qp32CudKjf6mm76Kl5mxMsdxA+KFxUp7fA7u7WrPPiBTpCWGulIj+QoB6sjf9p9jbL0acqDssqQxwRoSEyEqGtiEgKLcaXxF6rlTXFtpyX66SWfRDevjNNNdYmILMo/ZDWkgq40aQTEA+/96vi3i1uX6VvtaFJmnuo++elUFaCCnc+hfZMm+T+Fbxx5MfyTKcMa24ftbLH7h41euORTSnjwpkkpRjMejYPCA3SLIaF9g==; 5:QNjJ2AEEnrdsICBqTk+7BadAzWLprABsP2jKcCjRoBEZ3z5JGmKCaS9TN1hDJFuqIfuik6Em7O6bYWSs0i7+/hmkOD56my4osNaXjSkE8dEVjXD4phTrLFJX6kBOziuQVMJh4L4f9VJXr0rvmDgxdcMHkbJGIiMTF7afi7TYylw=; 24:7GiVdIsEzcThAKQwNq9ilYTYi0ty8RYeb6gJlOmMNmxFS2r1Si4q52cyFOSkLR77BWOQgl4L1MpGmsiwSironlOjkwQv3LCZTVD4gRZCfGA= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; VI1PR06MB1680; 7:oo1OmCekb1O2zB7ATAaU/Ayt92sgWlX5N9y4XR7RD78Z6zxhPrbsVdtH4wW/Si9fvB1DJazwT4M1noPcMbZLYFgFCJxo94ZtN9kZhgBSL7s/WMvNA7zcAS7pUyvznmceNn3Ffh+KPOlEL+CzSA3+shbrzzerycffuG3X1zEQl7kqwu7oqatWG4LEPzhTu3mSa4I+g2onAKaIM8ol9xeUZ2nFRnDnQUUxrxdDYlliskiAgwfyEUEWruKrCYMOKAELp1hxcdqez2lBWNuOcnw6mNLJxzdqB+Z6sDI2TDtHjC8B2v+PnpxDtcE9chjaYBlIErebKpAwlnxSoS/aDgYDZ//gIdllvetzILX0K3I+Buk= X-OriginatorOrg: cern.ch X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Nov 2016 12:11:05.3081 (UTC) X-MS-Exchange-CrossTenant-Id: c80d3499-4a40-4a8c-986e-abce017d6b19 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=c80d3499-4a40-4a8c-986e-abce017d6b19; Ip=[188.184.36.16]; Helo=[CERNMX14.cern.ch] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR06MB1680 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 Updated version of the ltc2990 driver which supports all measurement modes available in the chip. The mode can be set through a devicetree attribute. Signed-off-by: Tom Levens --- Changes since v1: * Refactored value conversion (patch 1/3) * Split the devicetree binding into separate patch (patch 2/3) * Specifying an invalid mode now returns -EINVAL, previously this only issued a warning and used the default value * Removed the "mode" sysfs attribute, as the mode of the chip is hardware specific and should not be user configurable. This allows much simpler code as a result. Documentation/hwmon/ltc2990 | 24 ++++--- drivers/hwmon/Kconfig | 7 +-- drivers/hwmon/ltc2990.c | 167 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 159 insertions(+), 39 deletions(-) diff --git a/Documentation/hwmon/ltc2990 b/Documentation/hwmon/ltc2990 index c25211e..3ed68f6 100644 --- a/Documentation/hwmon/ltc2990 +++ b/Documentation/hwmon/ltc2990 @@ -8,6 +8,7 @@ Supported chips: Datasheet: http://www.linear.com/product/ltc2990 Author: Mike Looijmans + Tom Levens Description @@ -16,10 +17,8 @@ Description LTC2990 is a Quad I2C Voltage, Current and Temperature Monitor. The chip's inputs can measure 4 voltages, or two inputs together (1+2 and 3+4) can be combined to measure a differential voltage, which is typically used to -measure current through a series resistor, or a temperature. - -This driver currently uses the 2x differential mode only. In order to support -other modes, the driver will need to be expanded. +measure current through a series resistor, or a temperature with an external +diode. Usage Notes @@ -32,12 +31,19 @@ devices explicitly. Sysfs attributes ---------------- +in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V) +temp1_input Internal chip temperature in millidegrees Celcius + +A subset of the following attributes are visible, depending on the measurement +mode of the chip. + +in[1-4]_input Voltage at V[1-4] pin in millivolt +temp2_input External temperature sensor TR1 in millidegrees Celcius +temp3_input External temperature sensor TR2 in millidegrees Celcius +curr1_input Current in mA across V1-V2 assuming a 1mOhm sense resistor +curr2_input Current in mA across V3-V4 assuming a 1mOhm sense resistor + The "curr*_input" measurements actually report the voltage drop across the input pins in microvolts. This is equivalent to the current through a 1mOhm sense resistor. Divide the reported value by the actual sense resistor value in mOhm to get the actual value. - -in0_input Voltage at Vcc pin in millivolt (range 2.5V to 5V) -temp1_input Internal chip temperature in millidegrees Celcius -curr1_input Current in mA across v1-v2 assuming a 1mOhm sense resistor. -curr2_input Current in mA across v3-v4 assuming a 1mOhm sense resistor. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 45cef3d..f7096ca 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -699,15 +699,12 @@ config SENSORS_LTC2945 be called ltc2945. config SENSORS_LTC2990 - tristate "Linear Technology LTC2990 (current monitoring mode only)" + tristate "Linear Technology LTC2990" depends on I2C help If you say yes here you get support for Linear Technology LTC2990 I2C System Monitor. The LTC2990 supports a combination of voltage, - current and temperature monitoring, but in addition to the Vcc supply - voltage and chip temperature, this driver currently only supports - reading two currents by measuring two differential voltages across - series resistors. + current and temperature monitoring. This driver can also be built as a module. If so, the module will be called ltc2990. diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 0ec4102..e8d36f5 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -6,11 +6,7 @@ * * License: GPLv2 * - * This driver assumes the chip is wired as a dual current monitor, and - * reports the voltage drop across two series resistors. It also reports - * the chip's internal temperature and Vcc power supply voltage. - * - * Value conversion refactored + * Value conversion refactored and support for all measurement modes added * by Tom Levens */ @@ -21,6 +17,7 @@ #include #include #include +#include #define LTC2990_STATUS 0x00 #define LTC2990_CONTROL 0x01 @@ -35,32 +32,96 @@ #define LTC2990_CONTROL_KELVIN BIT(7) #define LTC2990_CONTROL_SINGLE BIT(6) #define LTC2990_CONTROL_MEASURE_ALL (0x3 << 3) -#define LTC2990_CONTROL_MODE_CURRENT 0x06 -#define LTC2990_CONTROL_MODE_VOLTAGE 0x07 +#define LTC2990_CONTROL_MODE_DEFAULT 0x06 +#define LTC2990_CONTROL_MODE_MAX 0x07 + +#define LTC2990_IN0 BIT(0) +#define LTC2990_IN1 BIT(1) +#define LTC2990_IN2 BIT(2) +#define LTC2990_IN3 BIT(3) +#define LTC2990_IN4 BIT(4) +#define LTC2990_CURR1 BIT(5) +#define LTC2990_CURR2 BIT(6) +#define LTC2990_TEMP1 BIT(7) +#define LTC2990_TEMP2 BIT(8) +#define LTC2990_TEMP3 BIT(9) + +static const int ltc2990_attrs_ena[] = { + LTC2990_IN1 | LTC2990_IN2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_IN3 | LTC2990_IN4, + LTC2990_TEMP2 | LTC2990_CURR2, + LTC2990_TEMP2 | LTC2990_TEMP3, + LTC2990_CURR1 | LTC2990_CURR2, + LTC2990_IN1 | LTC2990_IN2 | LTC2990_IN3 | LTC2990_IN4 +}; + +struct ltc2990_data { + struct i2c_client *i2c; + u32 mode; +}; /* Return the converted value from the given register in uV or mC */ -static int ltc2990_get_value(struct i2c_client *i2c, u8 reg, s32 *result) +static int ltc2990_get_value(struct i2c_client *i2c, int index, s32 *result) { s32 val; + u8 reg; + + switch (index) { + case LTC2990_IN0: + reg = LTC2990_VCC_MSB; + break; + case LTC2990_IN1: + case LTC2990_CURR1: + case LTC2990_TEMP2: + reg = LTC2990_V1_MSB; + break; + case LTC2990_IN2: + reg = LTC2990_V2_MSB; + break; + case LTC2990_IN3: + case LTC2990_CURR2: + case LTC2990_TEMP3: + reg = LTC2990_V3_MSB; + break; + case LTC2990_IN4: + reg = LTC2990_V4_MSB; + break; + case LTC2990_TEMP1: + reg = LTC2990_TINT_MSB; + break; + default: + return -EINVAL; + } val = i2c_smbus_read_word_swapped(i2c, reg); if (unlikely(val < 0)) return val; - switch (reg) { - case LTC2990_TINT_MSB: - /* internal temp, 0.0625 degrees/LSB, 13-bit */ + switch (index) { + case LTC2990_TEMP1: + case LTC2990_TEMP2: + case LTC2990_TEMP3: + /* temp, 0.0625 degrees/LSB, 13-bit */ *result = sign_extend32(val, 12) * 1000 / 16; break; - case LTC2990_V1_MSB: - case LTC2990_V3_MSB: - /* Vx-Vy, 19.42uV/LSB. Depends on mode. */ + case LTC2990_CURR1: + case LTC2990_CURR2: + /* Vx-Vy, 19.42uV/LSB */ *result = sign_extend32(val, 14) * 1942 / 100; break; - case LTC2990_VCC_MSB: - /* Vcc, 305.18μV/LSB, 2.5V offset */ + case LTC2990_IN0: + /* Vcc, 305.18uV/LSB, 2.5V offset */ *result = sign_extend32(val, 14) * 30518 / (100 * 1000) + 2500; break; + case LTC2990_IN1: + case LTC2990_IN2: + case LTC2990_IN3: + case LTC2990_IN4: + /* Vx: 305.18uV/LSB */ + *result = sign_extend32(val, 14) * 30518 / (100 * 1000); + break; default: return -EINVAL; /* won't happen, keep compiler happy */ } @@ -72,48 +133,104 @@ static ssize_t ltc2990_show_value(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ltc2990_data *data = dev_get_drvdata(dev); s32 value; int ret; - ret = ltc2990_get_value(dev_get_drvdata(dev), attr->index, &value); + ret = ltc2990_get_value(data->i2c, attr->index, &value); if (unlikely(ret < 0)) return ret; return snprintf(buf, PAGE_SIZE, "%d\n", value); } +static umode_t ltc2990_attrs_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct ltc2990_data *data = dev_get_drvdata(dev); + struct device_attribute *da = + container_of(a, struct device_attribute, attr); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + if (attr->index == LTC2990_TEMP1 || + attr->index == LTC2990_IN0 || + attr->index & ltc2990_attrs_ena[data->mode]) + return a->mode; + else + return 0; +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_TINT_MSB); + LTC2990_TEMP1); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP2); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_TEMP3); static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V1_MSB); + LTC2990_CURR1); static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_V3_MSB); + LTC2990_CURR2); static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ltc2990_show_value, NULL, - LTC2990_VCC_MSB); + LTC2990_IN0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc2990_show_value, NULL, + LTC2990_IN4); static struct attribute *ltc2990_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, NULL, }; -ATTRIBUTE_GROUPS(ltc2990); + +static const struct attribute_group ltc2990_group = { + .attrs = ltc2990_attrs, + .is_visible = ltc2990_attrs_visible, +}; +__ATTRIBUTE_GROUPS(ltc2990); static int ltc2990_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { int ret; struct device *hwmon_dev; + struct ltc2990_data *data; + struct device_node *of_node = i2c->dev.of_node; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - /* Setup continuous mode, current monitor */ + data = devm_kzalloc(&i2c->dev, sizeof(struct ltc2990_data), GFP_KERNEL); + if (unlikely(!data)) + return -ENOMEM; + data->i2c = i2c; + + if (!of_node || of_property_read_u32(of_node, "lltc,mode", &data->mode)) + data->mode = LTC2990_CONTROL_MODE_DEFAULT; + + if (data->mode > LTC2990_CONTROL_MODE_MAX) { + dev_err(&i2c->dev, "Error: Invalid mode %d.\n", data->mode); + return -EINVAL; + } + + /* Setup continuous mode */ ret = i2c_smbus_write_byte_data(i2c, LTC2990_CONTROL, LTC2990_CONTROL_MEASURE_ALL | - LTC2990_CONTROL_MODE_CURRENT); + data->mode); if (ret < 0) { dev_err(&i2c->dev, "Error: Failed to set control mode.\n"); return ret; @@ -127,7 +244,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, hwmon_dev = devm_hwmon_device_register_with_groups(&i2c->dev, i2c->name, - i2c, + data, ltc2990_groups); return PTR_ERR_OR_ZERO(hwmon_dev);