From patchwork Thu Dec 12 21:00:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 13905993 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C5C4BE77180 for ; Thu, 12 Dec 2024 21:03:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:MIME-Version:Cc:To: In-Reply-To:References:Message-Id:Content-Transfer-Encoding:Content-Type: Subject:Date:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Mu/LPt3yx4FBUCM4QCAaFywQ/R9bTTHrooRW+dw8ym0=; b=EGu0+RRaLetITw6yX+GFwNyoyR QVFAB8MncTdxEQ3QES0iqZVY3XSXprOr+tnxcBP8X1MXMvhIvfST/I5rFcEwfdj308J6u7WIDHOoo Aase/Ki+LSWNoHAq4BgZqhHe5MmxIpPRHS1wI3joScf9ivigPLIT9tRmNgXFDfq0pk8g7FAxUeqyi pH3EQ2QSBvk/TAdzYdr8lHOvh+e86pkLpV+ICFzyFJ4wTnVOUi1NFtdzSB2s1dkXRxofAxmoqu67q 3nNxwWM55ouGneHlq4WSkXRDfgygsqkmmDvl18Jtr7ydtCxqj2vo+OKJybawzAIdoQzJ0Udn8qJe/ tFiz1AxQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tLqLc-00000001tNP-1RX8; Thu, 12 Dec 2024 21:03:48 +0000 Received: from mail-am6eur05on20621.outbound.protection.outlook.com ([2a01:111:f403:2612::621] helo=EUR05-AM6-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tLqIY-00000001sro-0VjT for linux-arm-kernel@lists.infradead.org; Thu, 12 Dec 2024 21:00:39 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MyCyVS46FlKIVMj6CL10Q7uZ6kOSkU9fMLmzVvghEBoF3TvjXUuEmzAOUC2W9JSUjEFK8k+v3jhjMYlr0toUPRHPx02HBWhj8wzuzPQTxBpi9im5+WA/wEcRu3Cuj1I0NhvtZSL4Le/hD2zUAM0ILeKq0RBX9YKVEM07BzIK38R+2xSIpJW4NwJKb8N3C00dIJrqpj479z7NGpZQhgs4KRjaeghQ0JY0SZbo+SPyd28tuoDYR4Ux4DocFRh72rxq9fmuwDYHSZFH7Zw1IHthpZUO1RB0pg6vAXUgNS1x86m/F/xaUBk08OS8X3r9MZ4JWda7sNyQ0ZFzr8KIr4mCCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Mu/LPt3yx4FBUCM4QCAaFywQ/R9bTTHrooRW+dw8ym0=; b=XKcaJX3vzM/Cv192XM7VI0ky4CcF1MHiieRdzRyO7Vjn72P6a+gSakKcC4X3cdD7rvGKJaoGJ2doyJSVLyoKXukqPjvk+N7BQg7GJEISyqcdXXPtifzGHMMBjcRTeOr0BlJl0yZhoCZTKH+antBMkufhN4NheqLHHD4F6Z1apNq0SVaXeWqjIT82yUvCjiCfGlxOPYofGNWbprsPVYO5VGxnebeKuhuCXCP777Xn/W/AA1PMqTHh5M3LDUQneemrlRJ7qRisOgmEVcEh3bjoWvoeOegneVydN3t9hc7i18HeL98tE64UQWiesd03lz6S8nUL5l2cKAFB03G+a6IvxA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Mu/LPt3yx4FBUCM4QCAaFywQ/R9bTTHrooRW+dw8ym0=; b=FjHq1LnrsfqsV6LltyB0hWf9C+SGdkFoLu31f0eyKdD0wwVe7SMDPAp+tYLFHnI1B6KgjsmFZW4yaeqetYIOWBiDsOkGbv0WQjrDct1pqZKGwtZNt9f/WNvchHlsUciLX1KH+0aRS3aFwFv8qUu3pdjU9dO6HYM96PgH4L3WzPykgmnjUkd7bU2D/SgqI+A95IxP8qXxbZVLv9SPzF329Cra272wPVMyEynGMueGdD71jzX0YDGOVV0GnAC4binvsEKC6LU1SscpequRRzRHSG7DeVaqRnbGHrRSNudir+4ok2yuopX6pnx7zBeEFmI4BEaeKr+s02kK0czb80pqLQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by AS8PR04MB7560.eurprd04.prod.outlook.com (2603:10a6:20b:29d::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8251.15; Thu, 12 Dec 2024 21:00:34 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::9126:a61e:341d:4b06]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::9126:a61e:341d:4b06%5]) with mapi id 15.20.8230.010; Thu, 12 Dec 2024 21:00:34 +0000 From: Frank Li Date: Thu, 12 Dec 2024 16:00:00 -0500 Subject: [PATCH v3 2/2] thermal: imx91: Add support for i.MX91 thermal monitoring unit Message-Id: <20241212-imx91tmu-v3-2-85e756b29437@nxp.com> References: <20241212-imx91tmu-v3-0-85e756b29437@nxp.com> In-Reply-To: <20241212-imx91tmu-v3-0-85e756b29437@nxp.com> To: "Rafael J. Wysocki" , Daniel Lezcano , Zhang Rui , Lukasz Luba , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , Pengfei Li , Marco Felsch Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Frank Li , Peng Fan X-Mailer: b4 0.13-dev-e586c X-Developer-Signature: v=1; a=ed25519-sha256; t=1734037218; l=10296; i=Frank.Li@nxp.com; s=20240130; h=from:subject:message-id; bh=6kF2c/YSx7LoiU1VwjjvTmVypq+sG5LudLSU6kO8t+s=; b=7kTtNd81/dyL1DLuudNWdlLADsuauzCtqndFgzkp7zaFu/ihOXh/icfaiwfUtmM1H2jB7ehSH JkQ1kqAbi+IDzusOb+h77Ah6XbpkF2Q5CbEJ+JPIWed+Pz/2P6ClQyf X-Developer-Key: i=Frank.Li@nxp.com; a=ed25519; pk=I0L1sDUfPxpAkRvPKy7MdauTuSENRq+DnA+G4qcS94Q= X-ClientProxiedBy: BY3PR05CA0025.namprd05.prod.outlook.com (2603:10b6:a03:254::30) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|AS8PR04MB7560:EE_ X-MS-Office365-Filtering-Correlation-Id: 5d5223f8-a8ae-41f5-0a86-08dd1af0057c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|366016|376014|7416014|52116014|10070799003|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?q?O7/CO2hHOT2ZDHCx+03kemewmx8lrOK?= =?utf-8?q?LlbgyfmHxwd0duZMFqsbqXAVZxyolE0dUh3wnnQAklsU3n3CfnPospU3KQEb+LHOm?= =?utf-8?q?/fZbeADuWrgh+mm2I/4tfOt2eycH/vvDAcPw90Qu7JJvdqqs/BiPEWnJqIs3As47m?= =?utf-8?q?Idgy1HClQ6QHFAiFC5T6eEygVeN88Qt6OT+wzQw5mL6jnkVHc+125NOjul3Ic1qZ8?= =?utf-8?q?P1erIT3Vwg1R9hVI03dMQJWCqpm703CacFfD+pWIW35xJ7Eq8GOUyNmy3FWZCy5vP?= =?utf-8?q?40vH28KP+nhb8gNVH7ptv2t47ZQNj6708QSTcc8gIayExS5fkSJdhWTa19EzegPGA?= =?utf-8?q?3kZYXHeebLApIaMokLGb/+Yn6yO43hO6ELWVbukmwlyJ4e0FG+a/b2WV6TqNxx29L?= =?utf-8?q?iz5/lVBl1gPUMMdEdGDSTeVNz3dQKf5UUHjWavHTXqv8g1r1LgllKzdNS7etkJ79w?= =?utf-8?q?wDT+bI5+zxt9ysJgechb/HGu/aWGGmdp+feJPro09goEZ+M3/v2Vea8NRzfkrntnC?= =?utf-8?q?/Aq3PSOTHRW3BNNoxnYLpb7U6JSxHcJTXzW0Whm3zb08kBlFZE80g84TY41K+Psxc?= =?utf-8?q?AuSA/MAemv6sJ/bEsIC+GEs6EHZpQU/NaJdgzjfbBNToVV7seELgEDUWVXGA/uojp?= =?utf-8?q?LctSIpDsz1Bqcqa/jbdznHAMJH3zn+mEVLUUBV474uKYTA8eA0n6ArAoP4XbskPkV?= =?utf-8?q?8xCvY3kTqivjSTS012LdRf2zC/Ti7G2MaHD+N6N93wTf3YpgS1sSyt27fe76dGOnk?= =?utf-8?q?zP2q+W3IJUUbJv9V0TZH7hQM1el+oV7xtsuAaWifwUm7AEpWgJORbsxfNAhll8fXZ?= =?utf-8?q?E6Cw5S8IltDgSd3667AMzpL08rSZABf/IsrJ8Td7esmEjs8ZCcuj3xuJexVLff1PJ?= =?utf-8?q?PljZyIEv5c0abKOhgHoUx1Whkb5N6xplDWRFe2j5ISJUZ1hTpTQVIspKgfqnXZGnV?= =?utf-8?q?YAtC1GodvjMOntY57A8wtlriCAGAJBXH72u/ju86kM7FJoULkwAbUorTE4g5KMJJC?= =?utf-8?q?GNhrE/JbR0juZfbXp4Q7eJG7mBE9XVxOXdJYX88CPFyNPdzHlVNoK0xM1ex7Dhu1S?= =?utf-8?q?ynVQVhrzfJAWH+9QpSGYVyhYq+Qk+BID6mmby2keKbRmhNHQFCSlNyzcrgYsqojl7?= =?utf-8?q?jD7q2DDmYf7PLjkZZ3ZcVnnqTmDblkfeclpuwKJFCVMGbGSxvoKCnGfe/+nrqX5Zj?= =?utf-8?q?MBa1Mau3mV/jlsGR0gqnM6Up1EvlunSsSHEGmZn1tevgq9S7JWe3DFZPJSh+tLxC8?= =?utf-8?q?VaOpT1pcNHUt2QwukWZKC2I1zUXrq/lEBK1ICkuEU4eYydEJHwanIz8srzttNKsJX?= =?utf-8?q?8036MAI7CIscoy0EqqzLbyDnUna1TwGHwQ=3D=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PAXPR04MB9642.eurprd04.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(376014)(7416014)(52116014)(10070799003)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?p9aF/rMVA6cPVYxN2LoCTfyieieq?= =?utf-8?q?9zvvH94mFUxk/fCvT9lOYzglyDjnHpOGTrbta9wnuwuHSTm96Vdh6zApN9l35FBxc?= =?utf-8?q?ehFgW5PJOGsCturMovOJG2H8N9p0wLA0Bc+EBbAPLvBXjJpRWYMUaVfSkImgZ4GId?= =?utf-8?q?1Yr4+nhZWwNMrUMCdSHvkX/YFOiz05V5h1y98IX2VazSHiYa/9VB+WbIIXf09L/d4?= =?utf-8?q?ov30zBe4ojNy7dIE4YhgEsPs5mWbiSgdz/vRymddmajd4RoP++5EZMqEhTjgsoEJS?= =?utf-8?q?cvEeuK43Dkje0W1ynMFW1zyPRANzKYtgR3aJZE8ytcE42gvt3io+DRrAHZJnkbRhc?= =?utf-8?q?b1QjpISzRjEItiQKvXgiV/yzC/IWZGkxQZkKwmRcX8TjcRes+ctZDzIK+HhxQ5iHn?= =?utf-8?q?b76UUDtw374/I3NV89AF8CIRhdgodDDTDGsnhGzQxDHgLvY3jeHvuvnVk6NM5X3n7?= =?utf-8?q?yEJkopgrGyoZCqAkIVm7TbkigzG4JPbxnH35w4lYltbW+bokcNXehcCyBd6LQTjXE?= =?utf-8?q?/o83ulyH3RdP0t9Yb1DEiBApEvR/btI6m2j6U1zNMwmF9MiLr7BBTj2Bj3O+bplg7?= =?utf-8?q?iLnxbSW0BTih9O+fuIUdJYk60E8NptjM2P3tf/bKz5oDSpsaGiXa0qJzIB1AgIhlc?= =?utf-8?q?1iJUrk7Rurv0+bvJz4oyggCzI3A56gmfR0CoAVdC11V1NR7rDTLsy9DmmBRCmR8Co?= =?utf-8?q?Vv7x+EcqUPUuHt0exUUgRQeFU4dimr+fPJrJ1TujN/XKzyBSBXXIRm1ksyPf5ASLr?= =?utf-8?q?bMgE9NYTfhDFPdVFClbRIs7/M09kvenEQvQHdrDLNF9Q0xYZddb9bzsiB0SWjj6BL?= =?utf-8?q?rO/MkRFV0V/n4tW8OHaRvfHYulo+L5um3GIqK3PGGVm7giRMpHOFsaiS1Ukoe+sSy?= =?utf-8?q?yZ3Kd7ifoDuHrg85w5d9cTtw/YDI1hYTbeLFzXOEZBnMyoCrktvAoRxW76FtX8OC/?= =?utf-8?q?LDKg+hGFVnqyX4SD00aUTctjbfF1yJiZTPleo3kupA2gCoiOalXAURq4nbLHxu47q?= =?utf-8?q?JNeHktRs0K9ZEJmg/uExb6MPlhkS3ZxvapxBnKz/9c/DZpD3ZjziR/Gc5KuTejJSe?= =?utf-8?q?kgTe3sO7xqKb65XywkfqQ8XGZlzGTEkDA2XqIKF4LHpkeHT99HNBodvsa9h9bTSHx?= =?utf-8?q?rN5sfwuLv0j0WuNgI9O5jt1/TO/Ly410lCTBaS+wTaYXZAGC7DDc7hzgPoxZ5F4Mj?= =?utf-8?q?aKJOnyUq41c+AUxQi3eyd0UQvoAI0L3o634MTSbRkUgdTID5QIGdC1Xo7EPmm8P7K?= =?utf-8?q?HJV1CVcfNa9w9SvZxY4AtxfrrCCWnIJ2jrjkFsnRa/JSXfPmkrl/QQ3uAfxJPStYZ?= =?utf-8?q?k8gaJZZWWPRWWP7jHmr3lq8ZvmYkSMZkm1UfPICLyBONjuTmPrkkCldJ2oYc8Y31b?= =?utf-8?q?zeoQ+jsSnOMCV//TJvjujQGoLvdWE7MLyPKmNe0sQ0DKW96643V4ST+bOCmbxu7Cp?= =?utf-8?q?ZaiO9iqfCZRf8eUMCyN+dAhCbGoKfbnMpkcX6XFuQX51yVAlcJBpzVB9c+rog1TaN?= =?utf-8?q?dYjz1VKZtxSwnIsxyxWsaHcEE/BbtG3dU3UnqJew5/H7VpeqAAndJqw493lBrLdqL?= =?utf-8?q?Bek63svKdy7?= X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5d5223f8-a8ae-41f5-0a86-08dd1af0057c X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Dec 2024 21:00:34.5244 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: sPjDhVebg8V4T7X4l8e9xVY9PPxbtvZi9gx0+1+zqlkQqG8FKPXkY4Vu5SbgbidauB7VlvpgVil+k+vTLoKUtg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS8PR04MB7560 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241212_130038_316727_E18B9402 X-CRM114-Status: GOOD ( 18.78 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Pengfei Li Introduce support for the i.MX91 thermal monitoring unit, which features a single sensor for the CPU. The register layout differs from other chips, necessitating the creation of a dedicated file for this. Signed-off-by: Pengfei Li Signed-off-by: Peng Fan Signed-off-by: Frank Li Reviewed-by: Marco Felsch --- change from v2 to v3 - add IMX91_TMU_ prefix for register define - remove unused register define - fix missed pm_runtime_put() at error path in imx91_tmu_get_temp() - use dev variable in probe function - use pm_runtime_set_active() in probe - move START to imx91_tmu_get_temp() - use DEFINE_RUNTIME_DEV_PM_OPS() - keep set reset value because there are not sw "reset" bit in controller, uboot may change and enable tmu. change from v1 to v2 - use low case for hexvalue - combine struct imx91_tmu and tmu_sensor - simplify imx91_tmu_start() and imx91_tmu_enable() - use s16 for imx91_tmu_get_temp(), which may negative value - use reverse christmas tree style - use run time pm - use oneshot to sample temp - register thermal zone after hardware init --- drivers/thermal/Kconfig | 10 ++ drivers/thermal/Makefile | 1 + drivers/thermal/imx91_thermal.c | 263 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index d3f9686e26e71..da403ed86aeb1 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -296,6 +296,16 @@ config IMX8MM_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config IMX91_THERMAL + tristate "Temperature sensor driver for NXP i.MX91 SoC" + depends on ARCH_MXC || COMPILE_TEST + depends on OF + help + Support for Temperature sensor found on NXP i.MX91 SoC. + 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 K3_THERMAL tristate "Texas Instruments K3 thermal support" depends on ARCH_K3 || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 9abf43a74f2bb..08da241e6a598 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o +obj-$(CONFIG_IMX91_THERMAL) += imx91_thermal.o obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o diff --git a/drivers/thermal/imx91_thermal.c b/drivers/thermal/imx91_thermal.c new file mode 100644 index 0000000000000..62b579365fd03 --- /dev/null +++ b/drivers/thermal/imx91_thermal.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMX91_TMU_STAT0 0x10 +#define IMX91_TMU_STAT0_DRDY0_IF_MASK BIT(16) + +#define IMX91_TMU_DATA0 0x20 + +#define IMX91_TMU_CTRL1_SET 0x204 +#define IMX91_TMU_CTRL1_CLR 0x208 +#define IMX91_TMU_CTRL1_EN BIT(31) +#define IMX91_TMU_CTRL1_START BIT(30) +#define IMX91_TMU_CTRL1_STOP BIT(29) +#define IMX91_TMU_CTRL1_RES_MASK GENMASK(19, 18) +#define IMX91_TMU_CTRL1_MEAS_MODE_MASK GENMASK(25, 24) +#define IMX91_TMU_CTRL1_MEAS_MODE_SINGLE 0 +#define IMX91_TMU_CTRL1_MEAS_MODE_CONTINUES 1 +#define IMX91_TMU_CTRL1_MEAS_MODE_PERIODIC 2 + +#define IMX91_TMU_REF_DIV 0x280 +#define IMX91_TMU_DIV_EN BIT(31) +#define IMX91_TMU_DIV_MASK GENMASK(23, 16) +#define IMX91_TMU_DIV_MAX 255 + +#define IMX91_TMU_PUD_ST_CTRL 0x2b0 +#define IMX91_TMU_PUDL_MASK GENMASK(23, 16) + +#define IMX91_TMU_TRIM1 0x2e0 +#define IMX91_TMU_TRIM2 0x2f0 + +#define IMX91_TMU_TEMP_LOW_LIMIT -40000 +#define IMX91_TMU_TEMP_HIGH_LIMIT 125000 + +#define IMX91_TMU_DEFAULT_TRIM1_CONFIG 0xb561bc2d +#define IMX91_TMU_DEFAULT_TRIM2_CONFIG 0x65d4 + +struct imx91_tmu { + void __iomem *base; + struct clk *clk; + struct device *dev; + struct thermal_zone_device *tzd; +}; + +static void imx91_tmu_start(struct imx91_tmu *tmu, bool start) +{ + u32 val = start ? IMX91_TMU_CTRL1_START : IMX91_TMU_CTRL1_STOP; + + writel_relaxed(val, tmu->base + IMX91_TMU_CTRL1_SET); +} + +static void imx91_tmu_enable(struct imx91_tmu *tmu, bool enable) +{ + u32 reg = enable ? IMX91_TMU_CTRL1_SET : IMX91_TMU_CTRL1_CLR; + + writel_relaxed(IMX91_TMU_CTRL1_EN, tmu->base + reg); +} + +static int imx91_tmu_get_temp(struct thermal_zone_device *tz, int *temp) +{ + struct imx91_tmu *tmu = thermal_zone_device_priv(tz); + s16 data; + int ret; + u32 val; + + ret = pm_runtime_resume_and_get(tmu->dev); + if (ret < 0) + return ret; + + imx91_tmu_start(tmu, true); + + ret = readl_relaxed_poll_timeout(tmu->base + IMX91_TMU_STAT0, val, + val & IMX91_TMU_STAT0_DRDY0_IF_MASK, 1000, 40000); + if (ret) { + ret = -EAGAIN; + goto out; + } + + /* DATA0 is 16bit signed number */ + data = readw_relaxed(tmu->base + IMX91_TMU_DATA0); + *temp = data * 1000 / 64; + if (*temp < IMX91_TMU_TEMP_LOW_LIMIT || *temp > IMX91_TMU_TEMP_HIGH_LIMIT) + ret = -EAGAIN; + +out: + pm_runtime_put(tmu->dev); + + return ret; +} + +static struct thermal_zone_device_ops tmu_tz_ops = { + .get_temp = imx91_tmu_get_temp, +}; + +static int imx91_init_from_nvmem_cells(struct imx91_tmu *tmu) +{ + struct device *dev = tmu->dev; + u32 trim1, trim2; + int ret; + + ret = nvmem_cell_read_u32(dev, "trim1", &trim1); + if (ret) + return ret; + + ret = nvmem_cell_read_u32(dev, "trim2", &trim2); + if (ret) + return ret; + + if (trim1 == 0 || trim2 == 0) + return -EINVAL; + + writel_relaxed(trim1, tmu->base + IMX91_TMU_TRIM1); + writel_relaxed(trim2, tmu->base + IMX91_TMU_TRIM2); + + return 0; +} + +static int imx91_tmu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx91_tmu *tmu; + unsigned long rate; + u32 div; + int ret; + + tmu = devm_kzalloc(dev, sizeof(struct imx91_tmu), GFP_KERNEL); + if (!tmu) + return -ENOMEM; + + tmu->dev = dev; + + tmu->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(tmu->base)) + return dev_err_probe(dev, PTR_ERR(tmu->base), "failed to get io resource"); + + tmu->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(tmu->clk)) + return dev_err_probe(dev, PTR_ERR(tmu->clk), "failed to get tmu clock\n"); + + platform_set_drvdata(pdev, tmu); + + /* disable the monitor during initialization */ + imx91_tmu_enable(tmu, false); + imx91_tmu_start(tmu, false); + + ret = imx91_init_from_nvmem_cells(tmu); + if (ret) { + writel_relaxed(IMX91_TMU_DEFAULT_TRIM1_CONFIG, tmu->base + IMX91_TMU_TRIM1); + writel_relaxed(IMX91_TMU_DEFAULT_TRIM2_CONFIG, tmu->base + IMX91_TMU_TRIM2); + } + + /* The typical conv clk is 4MHz, the output freq is 'rate / (div + 1)' */ + rate = clk_get_rate(tmu->clk); + div = (rate / 4000000) - 1; + if (div > IMX91_TMU_DIV_MAX) + return dev_err_probe(dev, -EINVAL, "clock divider exceed hardware limiation"); + + /* Set divider value and enable divider */ + writel_relaxed(IMX91_TMU_DIV_EN | FIELD_PREP(IMX91_TMU_DIV_MASK, div), + tmu->base + IMX91_TMU_REF_DIV); + + /* Set max power up delay: 'Tpud(ms) = 0xFF * 1000 / 4000000' */ + writel_relaxed(FIELD_PREP(IMX91_TMU_PUDL_MASK, 100U), tmu->base + IMX91_TMU_PUD_ST_CTRL); + + /* + * Set resolution mode + * 00b - Conversion time = 0.59325 ms + * 01b - Conversion time = 1.10525 ms + * 10b - Conversion time = 2.12925 ms + * 11b - Conversion time = 4.17725 ms + */ + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_RES_MASK, 0x3), tmu->base + IMX91_TMU_CTRL1_CLR); + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_RES_MASK, 0x1), tmu->base + IMX91_TMU_CTRL1_SET); + + writel_relaxed(IMX91_TMU_CTRL1_MEAS_MODE_MASK, tmu->base + IMX91_TMU_CTRL1_CLR); + writel_relaxed(FIELD_PREP(IMX91_TMU_CTRL1_MEAS_MODE_MASK, IMX91_TMU_CTRL1_MEAS_MODE_SINGLE), + tmu->base + IMX91_TMU_CTRL1_SET); + + imx91_tmu_enable(tmu, true); + pm_runtime_set_active(dev); + devm_pm_runtime_enable(dev); + + tmu->tzd = devm_thermal_of_zone_register(dev, 0, tmu, &tmu_tz_ops); + if (IS_ERR(tmu->tzd)) + return dev_err_probe(dev, PTR_ERR(tmu->tzd), + "failed to register thermal zone sensor\n"); + + pm_runtime_put(dev); + + return 0; +} + +static void imx91_tmu_remove(struct platform_device *pdev) +{ + struct imx91_tmu *tmu = platform_get_drvdata(pdev); + + /* disable tmu */ + imx91_tmu_start(tmu, false); + imx91_tmu_enable(tmu, false); +} + +static int imx91_tmu_runtime_suspend(struct device *dev) +{ + struct imx91_tmu *tmu = dev_get_drvdata(dev); + + /* disable tmu */ + imx91_tmu_enable(tmu, false); + + clk_disable_unprepare(tmu->clk); + + return 0; +} + +static int imx91_tmu_runtime_resume(struct device *dev) +{ + struct imx91_tmu *tmu = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(tmu->clk); + if (ret) + return ret; + + imx91_tmu_enable(tmu, true); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx91_tmu_pm_ops, imx91_tmu_runtime_suspend, + imx91_tmu_runtime_resume, NULL); + +static const struct of_device_id imx91_tmu_table[] = { + { .compatible = "fsl,imx91-tmu", }, + { }, +}; +MODULE_DEVICE_TABLE(of, imx91_tmu_table); + +static struct platform_driver imx91_tmu = { + .driver = { + .name = "imx91_thermal", + .pm = pm_ptr(&imx91_tmu_pm_ops), + .of_match_table = imx91_tmu_table, + }, + .probe = imx91_tmu_probe, + .remove = imx91_tmu_remove, +}; +module_platform_driver(imx91_tmu); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("i.MX91 Thermal Monitor Unit driver"); +MODULE_LICENSE("GPL");