From patchwork Mon Dec 16 19:25:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 13910256 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 0B9A4E7717F for ; Mon, 16 Dec 2024 19:29:09 +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=NKFkLXzsPrMPAJ/AkNZ8x8fL9AgBS0//d+PC9EoobIM=; b=xzV3/5V0fTht1uJinecx6/ykDp 6QaruI+wjaXOa3RkVSDcqjRUfn26ikM9/9Qx7qmmzkDsmP7fnmp9dUkybS1vtonrceqBLOldDvaHo 9YJetJbnFfbrycpYf2d9OiFWw/Ogddyf9g5l1/C96tqrKlh64GldL3Wa73J1ZfkQec7QpJqUqf877 4e1fFou3170Il+gzVaFbk7xBDOOcK/LslDWQSrjk1mVuAIl5geHO3+th60dQn9jdVC9/cp2qpdmwI ikg2KN9kubnmC7QjBzeHNV0YY0OFTECBqsErpJYlftT+/197CMp/Wju3Lu+1FgH2RXNXaFXbFx4VW 3H4rH3FA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1tNGm3-0000000B6Zi-1fF8; Mon, 16 Dec 2024 19:28:59 +0000 Received: from mail-am6eur05on20628.outbound.protection.outlook.com ([2a01:111:f403:2612::628] helo=EUR05-AM6-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1tNGip-0000000B5dL-3VjX for linux-arm-kernel@lists.infradead.org; Mon, 16 Dec 2024 19:25:40 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=nTm/ox+n0TCpYnCkuzceftir3VUAxUkuADvG411WHJP5fhe1IAf4ZClFflY/cxAkxzauqTBE9qMhpPvsMQVvscEiIfhYQ0PR2Fj4LIi7BPnF+R3a5NZeQfNvTXjW9+qyqXoFMjQd+iV6L4cQ5zRfYayVKuR+nza8D00trtChuq9NGHmSX9Rguafnso4LbCpouzGoe0EtYSSP/+DBUh+48fJ9cfSBw6N9dUK06tQ/hxpbBx3TyAhFJBt+ZWbsCPdWH8AA1xOcUpC7mltzNgFN6DTnS9HiMlPir0DZ43EYvKpM9x0WPdBvl7qg+CLXjxcwQmvEf2di0PPgM8oYy10TTQ== 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=NKFkLXzsPrMPAJ/AkNZ8x8fL9AgBS0//d+PC9EoobIM=; b=q3p2jssLzlLyqrEUUgeQDMDIZO3DMwYJa2nuHxb7zv0FfWW1Erm936IS3gi7ilioEIhle+IWGiWX+DqsHcZ/Mvhw6+JvRz+QLrwS0y0Hl3h12u5zsA3Te9Mnxywg2jMC+fqIY1wW17ysWHg6TkjChCwgAZ9ifmzaNXPplTjqJ5XS7WHf93AJauev8BbTM/6s74KjGVvLLqmAIDqFzEnEjzKjSxrrDQ1XuO0IYoqMZaFpUZad67sm0EOCYfvz216yNXoYTIczPTHgn392xSUL7uwkwSQpYRoeSfsVdx31aNH2Ncpb9pATJTP2IBVQ8+L2JMU9P7kpbE9CUKEcn90ybA== 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=NKFkLXzsPrMPAJ/AkNZ8x8fL9AgBS0//d+PC9EoobIM=; b=XSKv23/6MM/MekLFFN5M8aYSykGyW24CMR+W+RjthrSYJrvS8UoxFqNjCJW6lNO0MErNap2Aa6W334F3oyAj/0kbxCXyEYyjeB7rUaX5BFalo0m3hfpg1TsIBWzjtQi+1hUIgqKDSVQzch9X62WwoTupENWwTw/jYcpNmYbA98Xx3sYP2SBhMdDHK6+KCAbS3E57B330DF7wsrVvhZ85vRQHMBcIS0DeHwNrMRRiqm/rR4tNZdZNDb+GkOzCMcqxugxbzF19XKF4DjCs+wiYsU7qeErMD7cX402ammGkNMYtoNsKDQBbJvliIv3Fvqy48wbO1qpyor5xxzJ9m7tGNw== 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 GV1PR04MB10249.eurprd04.prod.outlook.com (2603:10a6:150:1a4::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8251.20; Mon, 16 Dec 2024 19:25:36 +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.8251.008; Mon, 16 Dec 2024 19:25:36 +0000 From: Frank Li Date: Mon, 16 Dec 2024 14:25:15 -0500 Subject: [PATCH v4 2/2] thermal: imx91: Add support for i.MX91 thermal monitoring unit Message-Id: <20241216-imx91tmu-v4-2-75caef7481b8@nxp.com> References: <20241216-imx91tmu-v4-0-75caef7481b8@nxp.com> In-Reply-To: <20241216-imx91tmu-v4-0-75caef7481b8@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=1734377121; l=10515; i=Frank.Li@nxp.com; s=20240130; h=from:subject:message-id; bh=dTjQUl4h5prrPcKAUb7k5+VuHEpPWFNDFvgoXRWdg9s=; b=452e6c2wGvXh+swQBQAEYzet8wrY5KezCJxktvl3JXfktNnfH7QMluvQ3r9olYFPSblRhrsUK guD54nrVjHYAbIT2EL/We1HK4v1gg6BjZPBSvfbJUv7NfcgceV0UtS1 X-Developer-Key: i=Frank.Li@nxp.com; a=ed25519; pk=I0L1sDUfPxpAkRvPKy7MdauTuSENRq+DnA+G4qcS94Q= X-ClientProxiedBy: SJ0PR13CA0031.namprd13.prod.outlook.com (2603:10b6:a03:2c2::6) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|GV1PR04MB10249:EE_ X-MS-Office365-Filtering-Correlation-Id: 6f2e8d68-121f-4239-003d-08dd1e076aef X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|376014|7416014|1800799024|52116014|38350700014|921020; X-Microsoft-Antispam-Message-Info: =?utf-8?q?W02GvGzRULKlKOBupm/mYC83THBMlcj?= =?utf-8?q?2EwzjMltNmwr72qgbq1cXW+wsdNUBf+N7ghGT7O6cZon479C0TBQVjS+4RfDtnNAb?= =?utf-8?q?kvbqKo+aWU2/3RBwlxMdBl4Gu+GDOCDrrNX5gV1X+rhBroN16VZPZdxw7vyFqJZvn?= =?utf-8?q?GyblW3/BtMvtaLjpASFUaR9afdmkkh0XZQFAwqILjn15BPMr2cRUsidsAx92nwuNg?= =?utf-8?q?QBCPMpWBfj2WBA/ibosrRDa5XmZjFjDSuiruX10qZY7zkbXsMzyTNIE7hbkl2dLxo?= =?utf-8?q?K5wnZLmLIhFENepB2mAAIb4ZYEAGwRt4H+VDiMwVHgLK01s3KjG8oCn3JpUTg3FgL?= =?utf-8?q?YR5sqB+nN3I2HLAPacUOECOFf82x3eHo6Y8XKKE1VqDEgiuJh0Pj+VmhqRT0ubW6I?= =?utf-8?q?BdKtOYkkN45vEJEmEFeUP05k6ou/IW85M36+DEtWqpiL4ok2TU7eq8FWn1XBtTKkk?= =?utf-8?q?tAIbNulGcAu6bdXJu2hiiVfJAW389av/ugSEmKYx23iih2Qrm3Y373r+YBVypWHu/?= =?utf-8?q?v/ABjOLp9ZSS11NH6F873u4EVrB0xBbHItYY1WQCosSi19VM5KxAc5dzoED2g1idX?= =?utf-8?q?8t3LYQiagN5nrpbslZtWrpRqUeUpEiRSKTmmaBBnLpH9cIMxANpLbd+BVxlkk8uzc?= =?utf-8?q?BYm/gFpsGWsJdVyd1AHv74dOwbXhl5+rwFSQDZAJoqQ17Uz6ilElri3wwljYP8z6J?= =?utf-8?q?CJJdPEbfTmePIPyjblE9dvWiRCTPrwTQ5zTYRLekhL8tiuLE+Omcxtn/2FqQf6if0?= =?utf-8?q?Ij9U31ZbZt5Vy1CbOSyS4wlUBHx3KblXs010u1lcO2SHCRVF8lZFgLA4HVcwt8Q7L?= =?utf-8?q?KuKHrMMAgj4y0H/bAzUmCSFgjev5DrWzwy95SpIzBs6E7XiDMP3jO1H76gcIRRejg?= =?utf-8?q?/vbBV60Gj2ih7Pf/fGJHd+x3PhBi92avr93a/ojgoJmTJbytOH9PntmGAns4IVuvK?= =?utf-8?q?cixYY8n+bOtq9Wvq6PdqyxzIdD0hD0lZZmHPoFto1ccTW+MN/hxemhTHe4+/iZqT7?= =?utf-8?q?iK+Elbl59HrjBJ2rudv2b/3AO3FckWdNl0m3LSLPFraberF0huAbNwPxgVGOKu3s2?= =?utf-8?q?9FMHRThPQMb8j1JeXMI1UUnj5l0FlhFDZ1NW74XlsDXkNiu1qT/rIvWqESJ3tPprg?= =?utf-8?q?tcnMKlNpaQb3YJaDWYHuOgot4xZC1mlSTtabZQMK2s+JTF0/dAbsx5ZelJNMv+mUU?= =?utf-8?q?C32UoOHDIVaDARcjDQrVNrUYnGDdF3snb5C4JWhzCes8TDJwx42I7r63V4vBnFrSf?= =?utf-8?q?sN0T6zf9tIKOZl95v+ARVHFgvZ4f2NB9WAJ4EDAXIWjGfZeacOHxpzzLTTtmDTXi1?= =?utf-8?q?bFNs33baOUlQky18LIfGJcz/q0gwwMtkiOGcpcODgzyiahYo2+LEwA0CZ+PKlA3w+?= =?utf-8?q?c+ykdDRjroCE1T70K4lFYGUxQ2gVjD+UQ=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)(366016)(376014)(7416014)(1800799024)(52116014)(38350700014)(921020);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?aiaugH448mRABWPoEDrRSKM5z2wh?= =?utf-8?q?GUMtqnDBT28xxrRl3cabQY9HZ5dcuZ1I1cOXhfj/68K3+Ly9xyjINaz83E9KyrDT0?= =?utf-8?q?OhcbCcZdg16noJO3xd98/79tHMb5MvMQ9Gf+ZwwuOnl44jmghP9qaE5lZDoWyNKUl?= =?utf-8?q?sDsFi1/degP/6MtxIuipGhztU0fAyCILF1cW4RgT9Oz05kGTRFhjCVnNjavRXcAbr?= =?utf-8?q?w+rELdOzO5eJ7ErFw/abD2KsxDPSEGpH9PGXDQK1igYc2rh0vFxbhdZEJwj/Pjcgq?= =?utf-8?q?/TLc1GSkAFEBrDi+U42Md6czu20fh3RoCFQUXIHJ9al81qE7rkPkFpDMf8wNR8Z0y?= =?utf-8?q?Be32vhj/3Yvhz3sCTsJEo4QrPPnqF2f5V53hfIPxZYE7jl4zN1SzR9eLGGw41CK30?= =?utf-8?q?yyAI2PFuXxnXrPqZB7XMvXzWiMzo4HsyqCgXlZ0+mXN1LoUTv5u3t0psXfLuG7rQG?= =?utf-8?q?Wo95qYDMnMGETcyOWJb59656eeGwY21HhWLeBFVOseB437nD45BZgETjpnxw9WBbp?= =?utf-8?q?ffAFKgC4HXrHPWx7t7Wn9dh3paR/Cac5HdDAVtsOuOZcIWL++9aRRIov5C5ZyMPVg?= =?utf-8?q?0tU1K711WppvXj7LAXQm1R7jfBRI9VptbnSNnVs3MDH+a0YM46KfraYNWIG1iQShP?= =?utf-8?q?Qfz2IUSy3EpV8KVAHEkbQ0sdexrOby7Fc0sFRaYJWABhOBXfAOA1PdQutdAu471vG?= =?utf-8?q?tt5H+kPO7QQeleQWhhE++f7sBPVRPUjPJaocQsuQ62Mt4P0Klu7GNTTevp/A8hEUG?= =?utf-8?q?0n/q4kAOhKb6msAYe77xBs0/hgGT9yiMK06yCPzorCnEWvFBRwPdLkLgoU+WhSuLe?= =?utf-8?q?2hIiUFkLdaxUorQbJ1PvWivGCdeoeA+16fteYDI2t9a2coJLw5ZokOkSx8gsN+wRJ?= =?utf-8?q?WZmIFJAT+T3k+GxnIlyT/oCQYqzMaxdLMf9+2AulI/RBTJCJc1n626L83PEdcPc01?= =?utf-8?q?Kcii/hzzAc1LbVE5lWnyxxJlDGKa54nVsEqb5Mmw8PLnVAZWXQjHxc3URQmY9fFkZ?= =?utf-8?q?D71xagKntQq7nt/ST4CGSblk4QqNjir2u+NoRA8c3CqKiNzuc2/6c1/RrRtimZzTL?= =?utf-8?q?WqHQd4NnoRZ3e1cB2aIKL1Am4l7+ba9uCO8iLG+RES7+ur2IdOFo8+LNq5JgXf+CZ?= =?utf-8?q?fiXjKjjUxZAsOCggSQ40vX9biuPzUExxKsf0Hl/tx1T4eHhnr+J6unle+oUnt8/dj?= =?utf-8?q?+v4gEupkTOkNdQu4N2qOactXp+gyOLN40fr6U8sAxq9yvJSWuFNeV2wc62DPNWR46?= =?utf-8?q?4Oa3llvfkJ9rR4rT5PsrRV1ckqaFYfUxNoEznCR9aDhXP3dT8b8NKR8uWCgrRO2lz?= =?utf-8?q?9MtF14T/g5oYq+6l6GyX3S/MxtTHxFPNjDS1EkU8EQdSsZNHoO60VcfqjxPz2Sd8j?= =?utf-8?q?RX7JDO1Z3ggCFCr9N18g6MBnKMeFQ2dtnM+nj5FJ3zMhlmFrTH/reSuO6/6Mkzd1a?= =?utf-8?q?78sXRcJqom5+KdIx/umszYHI32IsOjSzNIDv3vFPppEMyyOyQ+g9IfCwl0MPQGZLx?= =?utf-8?q?r9hQVjXSTqeK?= X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6f2e8d68-121f-4239-003d-08dd1e076aef X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Dec 2024 19:25:36.5501 (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: gYK+uL7oFnDPpZAMxJeYrCF4n/Z4izQ7oXIqHhoxhEmOgNogtL+mEz+oC1bDBn3oCgcrvuWGk5Mrti5pmfE3aQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV1PR04MB10249 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241216_112539_894387_86F7D36C X-CRM114-Status: GOOD ( 18.62 ) 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 Reviewed-by: Marco Felsch Signed-off-by: Frank Li --- Change from v3 to v4 - Add Macro's review tag - Use devm_add_action() - Move pm_runtim_put before thermal_of_zone_register() 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..ef5e8e181dd0f --- /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 void imx91_tmu_action_remove(void *data) +{ + struct imx91_tmu *tmu = data; + + /* disable tmu */ + imx91_tmu_enable(tmu, false); +} + +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 limitation"); + + /* 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); + + pm_runtime_set_active(dev); + devm_pm_runtime_enable(dev); + pm_runtime_put(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"); + + ret = devm_add_action(dev, imx91_tmu_action_remove, tmu); + if (ret) + return dev_err_probe(dev, ret, "Failure to add action imx91_tmu_action_remove()\n"); + + return 0; +} + +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, +}; +module_platform_driver(imx91_tmu); + +MODULE_AUTHOR("Peng Fan "); +MODULE_DESCRIPTION("i.MX91 Thermal Monitor Unit driver"); +MODULE_LICENSE("GPL");