From patchwork Fri Jun 3 06:57:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hongtao Jia X-Patchwork-Id: 629635 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rLbLS5Wt2z9t5x for ; Fri, 3 Jun 2016 17:28:48 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3rLbLS4bfZzDrC9 for ; Fri, 3 Jun 2016 17:28:48 +1000 (AEST) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Received: from na01-bl2-obe.outbound.protection.outlook.com (mail-bl2on0063.outbound.protection.outlook.com [65.55.169.63]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3rLbDv1tkGzDqmB for ; Fri, 3 Jun 2016 17:23:58 +1000 (AEST) Received: from BLUPR0301CA0029.namprd03.prod.outlook.com (10.162.113.167) by BY2PR0301MB1590.namprd03.prod.outlook.com (10.163.28.20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.511.6; Fri, 3 Jun 2016 07:08:14 +0000 Received: from BL2FFO11FD013.protection.gbl (2a01:111:f400:7c09::194) by BLUPR0301CA0029.outlook.office365.com (2a01:111:e400:5259::39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.506.9 via Frontend Transport; Fri, 3 Jun 2016 07:08:13 +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=none action=none header.from=nxp.com; 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 BL2FFO11FD013.mail.protection.outlook.com (10.173.160.221) with Microsoft SMTP Server (TLS) id 15.1.497.8 via Frontend Transport; Fri, 3 Jun 2016 07:08:13 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id u5377hfc000348; Fri, 3 Jun 2016 00:08:08 -0700 From: Jia Hongtao To: , , , , , Subject: [PATCH 7/7] thermal: qoriq: Add thermal management support Date: Fri, 3 Jun 2016 14:57:39 +0800 Message-ID: <1464937059-19349-7-git-send-email-hongtao.jia@nxp.com> X-Mailer: git-send-email 2.1.0.27.g96db324 In-Reply-To: <1464937059-19349-1-git-send-email-hongtao.jia@nxp.com> References: <1464937059-19349-1-git-send-email-hongtao.jia@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131094112934938662; (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)(2980300002)(1109001)(1110001)(339900001)(199003)(189002)(9170700003)(36756003)(106466001)(229853001)(6806005)(5003940100001)(104016004)(2950100001)(586003)(8676002)(33646002)(8666004)(8936002)(189998001)(105606002)(50226002)(4326007)(85426001)(77096005)(50466002)(2906002)(5008740100001)(19580405001)(50986999)(19580395003)(92566002)(11100500001)(81166006)(87936001)(47776003)(2201001)(76176999)(48376002)(5001770100001)(86362001)(575784001)(7059030)(2101003)(473944003); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR0301MB1590; H:az84smr01.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD013; 1:ldbBw89wQUyH2azBUZ4VWqxJEUpLOE2DhyHmmyXSI0AYbfOPYctuUrtK32mty3zt63eQp4CiQnA+NSMuTzmOk0FhalRUkycqjz24dd0bYILDM8/lSjy9pv+FvxGR0swNfO6yeM9KWm31VhBF5a/XZy9xuvUvOIceuShDPnMHNVitjNw1njVO7uejM2IUJDf3A0etiyP7k1rlLu/dT0zIqeQx4+zj4ZGpqPS3Y8yG19VuwIp/NuX1VBLtbu/Q8vhbDcfBMcnju+GztdwqnUFAyGP4K2RTIEKbctAP3ZnEpPEIPr7D1rsZNZwhLnH0eqW6k0+XjLwltiqNNCm9dTPwbXNvPuTPLcCwVToCoJNjXq4EzuLW0oxIkgBIOVzwwF+TDFe/QB+/MY4iIV4SJTsrar7DEXViVZ/Me2TJecdf0pLpjrAAWwtK8E+4JiECSV2i4dyLeUg1SjJyQ2pUlEwfS9whcEjxE8QngLs6JgEc9mhbkxyE8VKHoHLEsK/kHMAMxooe3T8TZ32AwTc+5RZbcJ+flYcisBHCwUJiri2Np2H8t+1SDqAMj4YXlsFCaw/uLAznUnKsOwG0Y2fCEeTIK5kOUhsWIQKzAdTmdcM9BQ+zxiAl/NDD7DnTDZAQuLoF4+fqiEq6TYbYv1ut/SyGKsKAT8514Bgj6QO6qR2WDuFVcJJTi+nDPVcqirj9k884iAjceO807KCBEBfCgdi3ffPClO79BWz+5IxR+2iw/iM= MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 9380d3b8-f7de-4c93-fa5c-08d38b7dd400 X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB1590; 2:UFMtZ69NIszoO3HE/cDK5TFupEtzUdPTgqhuYuW8ASCCXHaR2HI3i/d1S/VYoIXMIFdJguiRkPLBvmJXjBBd/rMosoZtfjUGg4FvipMX+zYufYcfBlYJ6HdZh73twwo85f0NZH/mdSB0scawsHt/7FREwuvze/tLaCjsL0Y1Jy80YkH/Emyy8DxKnM4LZRmN; 3:i4ffdvicGl02TlboCmv4UrpDi+WPu3gqwEaCK6AGgLwJ/N3trMxF+a9eoUl5ab1ssyh1yUtkg6vUAlsH4GH0i6o0Pqp3v7JiqSmRNyz4MHK4r5InUEP8KCcb0mIj8uGqYp66i32WYaaeYl05cX5paLlc7dMGF5HYzfETOiFdQf7RNJ7n0qzNdS1Ca4duEQ969HSdKUCGiwHJvoPm+DaRACuAeY/TF9Sm5qQOUxEOSkQ=; 25:vUgPuoiZpUWTrqb6TIdLmIM5GeSJMp7bzkJ+s6p8yY9V+PIZAK+/BbQTrinb6Jm0X5hf6JUVXN66hXOgciyKrWq8IiYgzuaXDT8igmiE6WNAZQ8OaJ9I3vabcDCiXwdoacWjQm95e0NGXuet35VvFyeagfk5KeXMEfupnhugteMJsZhOQn2ABos9u2fWkIIZqwlY7QZgNal5mrllBfFW3NErfFhe2gTiaM9WgA5oz1jpeinKRlkqa2Gb9Z0WltMhpmxejhfSFFo2zb0wYUWLwWGUIAt44iif80MRqo1h7VBTn2YzZHWxKlUzZyolf+60vcBPjrsulNdxZDWa71CkUotSQMCTpxsrS1Jz8MjbysoL6HH9h0tlesiZOFjQ5ChXWNG+Gqy+OthBorUECKeI2LoCVoFVzGiIf+nxfqGsEHM= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR0301MB1590; 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)(13023025)(13017025)(13018025)(13024025)(13015025)(5005006)(8121501046)(3002001)(10201501046)(6055026); SRVR:BY2PR0301MB1590; BCL:0; PCL:0; RULEID:(400006); SRVR:BY2PR0301MB1590; X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB1590; 4:vDFRnpe9KfPcRtTldp+FNK2DcVfvHwoQDDwL/zPj5J2p6lcDdMy+iavx2FD5k7uo8RLd8vTkjusFGJavIThgcyc22gMQQXH1lzFl8vLROzFYBn7BEURZjayrEZ4r8XQuVYtHy2ZaGeuS7P+F6zbk9q4Ttmf8hnvLmfo9RIa/yWsupW75BnYFFMEsApsAtRUY1GVnkg57SOJ3CKHHetA59baWxG8aqPvS0KwndwzXGMMUdmh8rdBYvQGlH7k8y+YsQrWLQWHutLXrU4UTSnEwg4e1kNrOvuCFO0eaPriS3TybesGG7pqXbpi3DGnxJlglDgch2plIl0cfZ2Wv6uQkOcKPCxjRY/gyN+SvUgZU+IRSLSdVNY+4RhndqOskj/LbapX+FuXOYTTw2DG+ytV7X7SOlXA3zyFxDDi86Wbc4CUOH2mpIL09w9GzxyEohXpksq4pw+CjOqOz/e5t2A4Ggg52nK7voNhMmHYnl0Pr1Xr5ukpvtj8aiJLRVAJRHfPuuiMFu/Udwne3oQpnc3f2rQ0wMXtsUgqBhFxiAcMGWBggvTJSgsWYt5WuvZpd6JM6 X-Forefront-PRVS: 0962D394D2 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2PR0301MB1590; 23:a8JF/2O1B6waDc325hF6QUPWNd7TxGJ3wmI5GJ6?= =?us-ascii?Q?58DkA+KgYdJ0+lGx8zK4ne4ZibIGOBLtUVc+SmtEL9TNgEkbGCGAnJbHOL7R?= =?us-ascii?Q?VHh3YEysyFuNgB8qjZPPC3aEGRfjry5+eukgo4x15g61wR11Oks2vHlS8hiq?= =?us-ascii?Q?1r3Jlm/Rbjp+zPyU4lkGa8m2nxHORBxMMJnxoPF3qeZ1JeGQ6HVJcDSzX94E?= =?us-ascii?Q?EXn25reFONk8DGY2Vq7xHalTLS8zDKzabuVKTEUaO3lur5QCdVuqNfLSapbt?= =?us-ascii?Q?Ut0N+u/SRaJ9nUzsI9C00J+6LjueV1RDtmtX4s6jWKUuPTxg8xm0LV329YXp?= =?us-ascii?Q?2SgAzVtdSmIxvuC80mzAoIHAsu2dJ8KMuV20APf5bLO9kYPXAQ/jfZOy0imv?= =?us-ascii?Q?mswHUT8yxDj9z6hoP/fJ/+ifZOcsMOL4Hd12rTe50Dd8qF++fNC08q+703GP?= =?us-ascii?Q?wbu8O4KIceLXZ8LnLRS2yI5WgN00KHYQyIY2AcE+NSOx1mHO3pu6q090DybM?= =?us-ascii?Q?2zXN9V+fhpnYUUAWoNG/LgXX9XyQRKtv13vGCpuONreCNjX/4B+HJLaXACiZ?= =?us-ascii?Q?OYnfIkj6vxfiGNCfqtSqX2waqicH4yqA6MIeP3EyFVTGA6GpU1FJ9DSy4ZDR?= =?us-ascii?Q?iBVNCL6CStmyM6KYmBOlSB1wjKK2SGzsCroU8XJkIujOMSD2VxT9Kv/dSQba?= =?us-ascii?Q?t850kwBy6FdbdDRHPACjxWAkNJOfGufnzllzG43qdrXsGNapBXK64FDp5itF?= =?us-ascii?Q?3RQqy3X6xQujW8xQQF1V/YL2/rI1ijY1nNc/cXPS6bOtaTBVoYXKCibIJoEF?= =?us-ascii?Q?g8aFy7cQYcL0B4Ho7L/Q1XWFO1MjM3X0EuaeQR1b68wMyG+7OCwTHyX7bEYI?= =?us-ascii?Q?uoY3TgipGdzT762l9I+xd3rpWjCoe//CM8fc123fqvleaeHE4zvDvEppXMoF?= =?us-ascii?Q?n6lO7GrJNPonhNlrvIbswW2bXC6nyDKiTxNb2eXmzNe8qb0chfvKEclhbSUb?= =?us-ascii?Q?HZYxt+y1cGFjzHKxBNWDzX8OS9KCWyt9jGIqYeTmVA/aOlncKHBb25AiVwaU?= =?us-ascii?Q?UEvo6KDcyt4rsQmNOg5mJuXLAfcgaLXRJcalTA8QgHX9O8YYMFL4EYM0C7uJ?= =?us-ascii?Q?3Gin7aPvsfkUInfEIKFGMVK4b4lSG6BDU5qRjOh+Cl29J/xWItHT7I5u8aP6?= =?us-ascii?Q?hYsp3RbVZNqEXDWI=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB1590; 5:3rxGpLLQ1oU/wcZTln7fibri/V9NlYSvA9XAhEES2+y8gfqTE/ZU6w76sOmPksndPrynu9hVofZxArf9WmOHHa+3VX5ubiSwziYkDrTTL6IRBw3XPw6Ho4RXKRaAiXfaGM8vOLIAxFrpslhVhH2vwHIFwI9SGheOJX+q+OGePQM=; 24:+cDneW1BK1TIeuoLslCJCTfve3B+ItM+tn1wAJqTz91r5BY0cuG5JLRj5MO3Hg1Aj1Inh8nG3Ji0VZJHtgAHKRevfADlgA8J1bbpbz9N/kg=; 7:81LFTLaHmpvEAiBZaM+4axrvaKG19wD/4ElbBR0henKcYBTVpdKrCb4AxAkodDd4SbaiXlGrfiqe59l2O9BBixvfVGWMHdQcyJ0wvDVRg3ximVFjEBAXFWpEISaJ+RNhKuOiHoEtet8xoZBq2S2mjzf1DrZsCzvcJK0pkrHEYTO/0Ta80YmbYgXuL97iKF6KMdTnXmwmhOqCGJtZ+/L/j1LnlocFMhqI+1GkUcHL7BM= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Jun 2016 07:08:13.1194 (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: BY2PR0301MB1590 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: Linux on PowerPC Developers Mail List 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 Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" 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 --- drivers/thermal/Kconfig | 9 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 328 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..bef26cd 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -195,6 +195,15 @@ 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 + 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");