From patchwork Thu Jun 30 03:08:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jia Hongtao X-Patchwork-Id: 9206553 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 2DC7860752 for ; Thu, 30 Jun 2016 03:21:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1DF30283EB for ; Thu, 30 Jun 2016 03:21:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0F9CB2864F; Thu, 30 Jun 2016 03:21:19 +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=-4.2 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3DAAA283EB for ; Thu, 30 Jun 2016 03:21:18 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bISW4-0003BB-8J; Thu, 30 Jun 2016 03:19:48 +0000 Received: from mail-bl2on0624.outbound.protection.outlook.com ([2a01:111:f400:fc09::624] helo=na01-bl2-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bISW0-000369-KS for linux-arm-kernel@lists.infradead.org; Thu, 30 Jun 2016 03:19:46 +0000 Received: from BY2PR03CA055.namprd03.prod.outlook.com (10.141.249.28) by CY1PR0301MB0857.namprd03.prod.outlook.com (10.160.163.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.523.12; Thu, 30 Jun 2016 03:19:22 +0000 Received: from BN1BFFO11FD006.protection.gbl (2a01:111:f400:7c10::1:142) by BY2PR03CA055.outlook.office365.com (2a01:111:e400:2c5d::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.523.12 via Frontend Transport; Thu, 30 Jun 2016 03:19:22 +0000 Authentication-Results: spf=fail (sender IP is 192.88.158.2) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none; nxp.com; dmarc=fail action=none header.from=nxp.com; nxp.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.158.2 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.158.2; helo=az84smr01.freescale.net; Received: from az84smr01.freescale.net (192.88.158.2) by BN1BFFO11FD006.mail.protection.outlook.com (10.58.144.69) with Microsoft SMTP Server (TLS) id 15.1.523.9 via Frontend Transport; Thu, 30 Jun 2016 03:19:17 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id u5U3JB0W024126; Wed, 29 Jun 2016 20:19:12 -0700 From: Jia Hongtao To: , , , , , Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support Date: Thu, 30 Jun 2016 11:08:38 +0800 Message-ID: <1467256118-41754-1-git-send-email-hongtao.jia@nxp.com> X-Mailer: git-send-email 2.1.0.27.g96db324 X-EOPAttributedMessage: 0 X-Matching-Connectors: 131117303616373747; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.158.2; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(1110001)(1109001)(339900001)(199003)(189002)(106466001)(105606002)(19580405001)(4326007)(50466002)(356003)(36756003)(8666005)(48376002)(586003)(19580395003)(47776003)(97736004)(69596002)(86362001)(2201001)(50986999)(189998001)(5001770100001)(2906002)(33646002)(85426001)(575784001)(8676002)(50226002)(81156014)(11100500001)(5003940100001)(229853001)(92566002)(305945005)(8936002)(68736007)(81166006)(77096005)(104016004)(87936001)(7846002)(6806005)(7059030)(2004002)(2101003)(473944003); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR0301MB0857; H:az84smr01.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BN1BFFO11FD006; 1:qSurV61slQmiB6ExsDoxpI4/3UuvfAPn739oS2wFNGoC0HxT/I4du8q3CJLTXIEqHCIot5Mdiw3N+KoTe3O73QRSxYmJXlkOhEyq0s3WqMORr2H01IsZu5UKvXPIOV8c/jTruVOBxUMmUagRXZQSSHmj1eL9mptbMFqL49fx2qR04j9Yabd94yGj3LdnCY1uef59LbnFFqALeCt2bjtPJFCOIC+feTNe7PFxg0vd16rcmyO4UkLpWePa/CoNdFBhQBZguQ1ke3uR/ZDkurUru0JGlzoLtkNLOgOIu5c3+5NBh4MrXCqOI0PTnCxautN6mme64T1gQCmaNUvmLdW2kC+xFBeSGNXVPJeRJCpypY45aqAcS0/6sxnIxlvyJavNUgc58jX+AWFvIs+Dw8nj1SxvcyuF2lECtEG9K0ndVGGwDoJv4xanQH7C+1t9iy2U06Qlqw4KHdHPE6oA76xXS9u070egKpiJDJ8nKIHzV+BEOg3o8XVtYrpVxmKVA9QGCJ2KOxm+B5igNviFzSkb56lm7GyZ6X94ds3my9He8kAZeYCXAXmCFOSlhGn+Wrtr+3hWFKq42+9K7QoLFLGaHsT7I4nnf0LZfjUZAvzLA394pm2o5TFAhGxp52G4KL9kfJEUuUkv6EFLF5qhu6+MpqGsS3fFhIcICCzSdNQ58CMD90S/Z6vHzaUJj0w39+kmavcH3LrTpdhpRZ3vtQw1FOEb6Hfpeho7Dtl+27MwkDHBoA1c63AQlWh6wWwoWKLK+75bh5hV4WxYWrUmvITPNw== MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 253f6e78-c9bf-44f9-a294-08d3a095546a X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0857; 2:T20HfH0cRFK7KXQNVUKLz2FfqEGAi7n3RhB/dUZPkKr6KaL5gHNNXge8xoaypAfFPpumzVuI2uaJyGVsZVLJJhAGAvQs4/OUp/TaCiIl+3jjJUMXhbKPMoBNsoW5wpTDbMSEexs71hN8+obsxBMbd0ARAuTJ3yVkSZ2+XcYwVHFebcUts5d8N+oSy5jBujz/; 3:jel93UkrVbVyC5c0n+QV4inpWanr5kBHE/3ofsZ1WAwBV+B5S4mGT9txs8gIVMqvyV5AyPgtKu3YzUCr9u66UupE9DgeJxYuGwU7LcKCx+vbDnOnWE/MwTdNQH6d+aR9HaXtfekwT31Ca/mnAHEkiRcb/ReT/zcpn3LG3l1v34es67RXr8vi5gheG+ZodKuH0KaUhQRRDGsnnIOloFF3Y+iXjNN+aJO0tTQD5ZtFZVw=; 25:xgsnTQEjjsyHR8wlgeGSx+gGFpzZiiyq+tM8VZN6IO5NqWbqRv+lUQ/IijbX1gRWubkKiUQLTUUOI/Gd9FfIcofj8hCZl5rWTq+6MDMcDUCVwxcqTVvV6V2fZ0wz+kZP3RcX3few7eO7G2h9lV+UUnG1gkvi3hSfImORTakA7VU77v8nocg730SXG+dIi1ObaA9d3M5YJv7/QXiVmVdBJO9+GK1nmx+7ITm48gDWhmaqU11KUDx73CqwQpQmf6MJcSDsKhJyln0jMsxdq/ysDkE4SGxDGjLqWYk6xS+SfKu9QCKq7XJMmVSXyC+7vZMIn8d0jO4IX/vfsdYs5w26g1JDdV/8DjylW2QHJi059qqqQi9ZggPTXNxSLyUxty/Q89KHesWoznr/Aa8yfY6zgS50BGsg+bn68wVYDk6U5GE= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR0301MB0857; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(72170088055959)(185117386973197); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(13017025)(8121501046)(13018025)(13024025)(13015025)(13023025)(10201501046)(3002001)(6055026); SRVR:CY1PR0301MB0857; BCL:0; PCL:0; RULEID:(400006); SRVR:CY1PR0301MB0857; X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0857; 4:O6mthJpYY4/493AJk+YCkXX/zfaWbluwKZTka7zt4sit3JcweglbHssBlIlDyoa1B4xtidg7QAVeNmoFA4GPrvGLi+YX0zYp0RJZcSZvMaOpeRdu8A8eH9ivNc0Xffwq4bc0jDTn9KmaOfLHeZtgH5eqiXxCmFJDIsvJToQB0RyRyVFoSdRZ0GwNG+ESgb3J822Yy81c5Aa1NPpeDhxGTgSOr9srBWJwQBsoHArheCJXatUiUBKUaL6ochl+RX4QxfEZ7AGwgBwxRKfv2KRnbfP3AgvFjaphA10InNtYcFaCS+a0hAtLSLOxlmMrnQPq2Z5tBGGuDu28kqe7smW2m6roGgmGBQgPwDWCdQbqp7QXcG7UOmb/yHsoToVs1rV51/ylRKB/QganeLqQTCStmkKUMrrvlOPiVLAp19eTZY30qqeJnmce3ic6Rbc+mAgIjjxI8ITkkSdgajF0vUshAuQWNTpbYEzhzJjLc3Ax1CQlakr/UpVtDQ4KixxNSLhBtC0wniRg/jNPo7j3D7cIpQ3NoRucBTIV5YRC81B+cFY5zXMjvj5m9X+f0ROIA80H X-Forefront-PRVS: 0989A7979C X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR0301MB0857; 23:4wZ8inMimUF8j5483w55mDUgQnMrtyCcflmH9bX?= =?us-ascii?Q?pUr4+IzhRX+eM2Of/GXn2/N0vdCeR0ctrXyM3ll4dBIGh/vcZJvAEdgsYhQB?= =?us-ascii?Q?Qq2gxzGdT12cZuQKOQWjXNWloQ7lj15ZmASEDu3cdBPUFylHlE+uDzZ8mvCC?= =?us-ascii?Q?4LyB7SxK5vyQ4XSTWy/InHQ1Tsyx0fR8ySTetCbyod8oWLpLBJxuoh82VuHH?= =?us-ascii?Q?aBfzJSBTRTco9azeB7VL85hLULeYhReLXzOVcc9hC+xUC3vCZLmpf4AvSOv+?= =?us-ascii?Q?jwVd4uMllyCKorhh0vr5mew2FeiOnshIILJsqvmDTtriEQsZ5XzJwsumst/B?= =?us-ascii?Q?508gvSLsWpsGYebVhv5vWydvtFURDo2+4f7iPtHSjRrkl8ByfCiIwKkn7+en?= =?us-ascii?Q?zZOLRx1jAqa/+qpVmZqQ+kUc45GwfXGg/1lT0AlcU4Hs95fh2j/8r6XEV9za?= =?us-ascii?Q?CwBxhWfjtfXUW/AIMPoWHvYu6V7uJdyNGij17aPSoFFajPJG04R0/1hR7T28?= =?us-ascii?Q?5CA3df0CRJFvONIPv3mGRoIGKhi1olpQt0ZSyNlHij8HpSNM9dbWoTd61bp5?= =?us-ascii?Q?Lqfo545IGSRxA2Jho61pICLR1g6JQLQFbphcU/DiKPzd7m/W2u8jYOUNqWs9?= =?us-ascii?Q?SiIwoCaIG7X8YRmxwTSZqrsKagKpnVXM+OECEwW7yL0sfRiNDCnUQzFCT+qS?= =?us-ascii?Q?ASLfpujhJLEIFKEeNB9v/8ZzNQF6w0F8uRA0z1PrNw/px65X/Lv+8xzUTI5u?= =?us-ascii?Q?OkFoxTGefj4sOejQZP84UE3NN/kevwlteLbwrCKqH46QwU+WTTMHNaFEgLx0?= =?us-ascii?Q?S81sHQ2uuv7KcsL4f3ki6jhhiPXep472wocif3ADj/VtWgFpSucQWstVsBYM?= =?us-ascii?Q?J+PJHEJJgecAAm2TDwO55aHWeqJPGP6OFKpVTLMdQO/49f8T1+c2N74FTxem?= =?us-ascii?Q?4583Cfk/hsBCmdf2ph5CCmz47mNW+di0Ko/aCsgewBpaKN3S4RdII+mCOuE7?= =?us-ascii?Q?RbsCvZvNUJ8IRY+kle5zX1+1vScpq4GQyScBe7UCQOYeYgd9sEuMLFi/Amr6?= =?us-ascii?Q?taYLv0mgqjsMX/zQc7+qlCytybJNS9eIBPE5EseZICTWRzKqi1e2Go19E5bh?= =?us-ascii?Q?VrZf/cgq2a5erEGOqW4rDJMlEB0Bm7PScRitYknP6bKL9n6RmNwb7Aiccpn4?= =?us-ascii?Q?/0mcwPpm04LEF/uMAom0hv99fAulhqFDBV14y8syxwMlZcWkZHXnGxw9RzQ?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR0301MB0857; 6:j2aGAR1zgRvuGkC5Rp/A1x1WXdb3hyEWcqQbGzpSUO4n9kOQW2XeYDVNkm76znJYJDsychjdcEjTFRZqo50woWzGwFaZ+xDA+eKU60cOy7EWQN0MLgnL1d5j0Qp9MSca7y4YEFET2UwWVNADNDzBcOeJj+5dBw3gZpTz0nJU8bEWE5OMYcto9sM6RyMgUjUYGFIrsRkefTY168unT1a0E2LknW0ysfdNrL3neT2pACb12eQRWLqc/aKju3sHquWAPq251EFO1HYmD/SZzf0kveX7SGmH69b3JUXQAjjGJ+ubBVASqDShEupAI4IZHZJp; 5:k1Th8yglCpu0xgpTZq1iYLv+q3564/XpsNqSKP9FP0Jo557/XvlAUxo/vpMHUXhzFDYtRTCStv7kYUKUJNFC+JYxaovKXtHbUR+aSd1h+JnVTKvz6zeZKx2FvYaMgaW8qLAYSEx/GN/Rfwb4f0A32VovzEygXbZZTsprkx364Mk=; 24:bMxtnegrA+RgfsD9J98baZ5nRfIKzYTE6Fw7J/k3IY3/KoO/xu0IHchsvy3+6Nr7C7bY59ikigjF1x0USYACzU2JcLeVvIU4fx3SZU0TFW0=; 7:+uxLOZNAkayqNFiKdwHPlvLoq5q/tfKQ1TGF4GtbRBZ6PGkWyWXqixOnzNaVwrzMu14ML12tOz5fkx00l1WY5sqf/ZjlJwkCjsDwKNgWfVWRFOj4Bfl9rvnpUPotJsX4HatcRTHaekgufrGXb80Cx5qyIyIeKdiHcLGptsb9skgF61PiK3iFvk0lOwA+OgQv7M4LSw23ndVrxjf3Bd0jGpBWyuCA2kk6rcxDkIOc+jmyA3tbUyumZAF82nNx0YBij69wGpUpwyR9y4HTPGwQRg== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Jun 2016 03:19:17.4722 (UTC) X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.158.2]; Helo=[az84smr01.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR0301MB0857 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160629_201944_982895_F01218FC X-CRM114-Status: GOOD ( 22.94 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, hongtao.jia@nxp.com, linuxppc-dev@lists.ozlabs.org, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This driver add thermal management support by enabling TMU (Thermal Monitoring Unit) on QorIQ platform. It's based on thermal of framework: - Trip points defined in device tree. - Cpufreq as cooling device registered in qoriq cpufreq driver. Signed-off-by: Jia Hongtao --- Changes of V2: * Add HAS_IOMEM dependency to fix build error on UM drivers/thermal/Kconfig | 10 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 328 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c -- 2.1.0.27.g96db324 diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..56ef30d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -195,6 +195,16 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config QORIQ_THERMAL + tristate "QorIQ Thermal Monitoring Unit" + depends on THERMAL_OF + depends on HAS_IOMEM + help + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 10b07c1..6662232 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new file mode 100644 index 0000000..644ba52 --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,328 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "thermal_core.h" + +#define SITES_MAX 16 + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct qoriq_tmu_regs { + u32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x0000000f + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + u32 tidr; /* Interrupt Detect Register */ + u32 tiscr; /* Interrupt Site Capture Register */ + u32 ticscr; /* Interrupt Critical Site Capture Register */ + u8 res1[0x10]; + u32 tmhtcrh; /* High Temperature Capture Register */ + u32 tmhtcrl; /* Low Temperature Capture Register */ + u8 res2[0x8]; + u32 tmhtitr; /* High Temperature Immediate Threshold */ + u32 tmhtatr; /* High Temperature Average Threshold */ + u32 tmhtactr; /* High Temperature Average Crit Threshold */ + u8 res3[0x24]; + u32 ttcfgr; /* Temperature Configuration Register */ + u32 tscfgr; /* Sensor Configuration Register */ + u8 res4[0x78]; + struct qoriq_tmu_site_regs site[SITES_MAX]; + u8 res5[0x9f8]; + u32 ipbrr0; /* IP Block Revision Register 0 */ + u32 ipbrr1; /* IP Block Revision Register 1 */ + u8 res6[0x310]; + u32 ttr0cr; /* Temperature Range 0 Control Register */ + u32 ttr1cr; /* Temperature Range 1 Control Register */ + u32 ttr2cr; /* Temperature Range 2 Control Register */ + u32 ttr3cr; /* Temperature Range 3 Control Register */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct qoriq_tmu_regs __iomem *regs; + int sensor_id; + bool little_endian; +}; + +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr) +{ + if (p->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) +{ + if (p->little_endian) + return ioread32(addr); + else + return ioread32be(addr); +} + +static int tmu_get_temp(void *p, int *temp) +{ + u32 val; + struct qoriq_tmu_data *data = p; + + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); + *temp = (val & 0xff) * 1000; + + return 0; +} + +static int qoriq_tmu_get_sensor_id(void) +{ + int ret, id; + struct of_phandle_args sensor_specs; + struct device_node *np, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + sensor_np = of_get_next_child(np, NULL); + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) { + of_node_put(np); + of_node_put(sensor_np); + return ret; + } + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + of_node_put(np); + of_node_put(sensor_np); + + return id; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const u32 *calibration; + struct device_node *np = pdev->dev.of_node; + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { + dev_err(&pdev->dev, "missing calibration range.\n"); + return -ENODEV; + } + + /* Init temperature range registers */ + tmu_write(data, range[0], &data->regs->ttr0cr); + tmu_write(data, range[1], &data->regs->ttr1cr); + tmu_write(data, range[2], &data->regs->ttr2cr); + tmu_write(data, range[3], &data->regs->ttr3cr); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { + dev_err(&pdev->dev, "invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = of_read_number(calibration, 1); + tmu_write(data, val, &data->regs->ttcfgr); + val = of_read_number(calibration + 1, 1); + tmu_write(data, val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + tmu_write(data, TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); +} + +static struct thermal_zone_of_device_ops tmu_tz_ops = { + .get_temp = tmu_get_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + const struct thermal_trip *trip; + struct qoriq_tmu_data *data; + struct device_node *np = pdev->dev.of_node; + u32 site = 0; + + if (!np) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -ENODEV; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + data->little_endian = of_property_read_bool(np, "little-endian"); + + data->sensor_id = qoriq_tmu_get_sensor_id(); + if (data->sensor_id < 0) { + dev_err(&pdev->dev, "Failed to get sensor id\n"); + ret = -ENODEV; + goto err_iomap; + } + + data->regs = of_iomap(np, 0); + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) + goto err_tmu; + + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, + data, &tmu_tz_ops); + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "Failed to register thermal zone device %d\n", ret); + goto err_tmu; + } + + trip = of_thermal_get_trip_points(data->tz); + + /* Enable monitoring */ + site |= 0x1 << (15 - data->sensor_id); + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); + + return 0; + +err_tmu: + iounmap(data->regs); + +err_iomap: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); + + iounmap(data->regs); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr &= ~TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr |= TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, + qoriq_tmu_suspend, qoriq_tmu_resume); + +static const struct of_device_id qoriq_tmu_match[] = { + { .compatible = "fsl,qoriq-tmu", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); + +static struct platform_driver qoriq_tmu = { + .driver = { + .name = "qoriq_thermal", + .pm = &qoriq_tmu_pm_ops, + .of_match_table = qoriq_tmu_match, + }, + .probe = qoriq_tmu_probe, + .remove = qoriq_tmu_remove, +}; +module_platform_driver(qoriq_tmu); + +MODULE_AUTHOR("Jia Hongtao "); +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2");