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: 850663 Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05on2043.outbound.protection.outlook.com [40.107.20.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 565F71C5F07; Thu, 12 Dec 2024 21:00:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.20.43 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734037240; cv=fail; b=XNMiWTZaUP8eS04LvCbcr+G1CGhzNlt3Qx1GCc5H2ctXBejPQmvbawXq/3F+Yeh/e62WJGC5XfJkQoq499m7aq+/Fkoh5xoW9/sIUWum+6lMqmOT5CeUIc8dMNWw5OYBKodmgJua9yOOPQ3z/wgl/ETdVarQQfm9Wc5OZxTKKiA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734037240; c=relaxed/simple; bh=pFRXWA2TwO/wUmImPmOAMiljT/WPmqaPXAbH6JQQMmY=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=TJEEBpQfnhzINYzbg9p1KFJU1gNvxQcp/9QiHggAJxt0EAWRu4ExzmAz4li49/0mh+rii5vRj8EbZdIt3aLitX98ar5xcPy7DvlN8Mwfl1P9L3xVavERLq+zpXOTeev966DInFGByQ1shsKCEymcxchvuUopNAJGoEOyBoCzux8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b=FjHq1Lnr; arc=fail smtp.client-ip=40.107.20.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nxp.com header.i=@nxp.com header.b="FjHq1Lnr" 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) Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 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");