From patchwork Wed Jul 29 06:19:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hongtao Jia X-Patchwork-Id: 501552 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 [103.22.144.68]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id E432B14030D for ; Wed, 29 Jul 2015 16:25:52 +1000 (AEST) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id C3BFD1A1D09 for ; Wed, 29 Jul 2015 16:25:52 +1000 (AEST) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Received: from na01-by2-obe.outbound.protection.outlook.com (mail-by2on0117.outbound.protection.outlook.com [207.46.100.117]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 87F441A0BBD for ; Wed, 29 Jul 2015 16:24:51 +1000 (AEST) Received: from BN3PR0301CA0028.namprd03.prod.outlook.com (10.160.180.166) by CY1PR03MB1485.namprd03.prod.outlook.com (10.163.17.158) with Microsoft SMTP Server (TLS) id 15.1.225.19; Wed, 29 Jul 2015 06:24:44 +0000 Received: from BN1BFFO11FD013.protection.gbl (2a01:111:f400:7c10::1:147) by BN3PR0301CA0028.outlook.office365.com (2a01:111:e400:4000::38) with Microsoft SMTP Server (TLS) id 15.1.225.19 via Frontend Transport; Wed, 29 Jul 2015 06:24:44 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=freescale.com; freescale.mail.onmicrosoft.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BN1BFFO11FD013.mail.protection.outlook.com (10.58.144.76) with Microsoft SMTP Server (TLS) id 15.1.231.11 via Frontend Transport; Wed, 29 Jul 2015 06:24:43 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id t6T6OeDE003893; Tue, 28 Jul 2015 23:24:41 -0700 From: Jia Hongtao To: Subject: [PATCH V2] QorIQ/TMU: add thermal management support based on TMU Date: Wed, 29 Jul 2015 14:19:39 +0800 Message-ID: <1438150779-22923-1-git-send-email-hongtao.jia@freescale.com> X-Mailer: git-send-email 2.1.0.27.g96db324 X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1; BN1BFFO11FD013; 1:Zk92AysmRYY4Seb2+aQI6z9My16U0JDMsMm77fsczasaXUTsWPpzMohc6IVlRcYLWJfgljEmctYbsJMmM7VzV/lPn5mb1ZAxMqM5N0JI0n6A3oTikETywOtnMjQpnBHUP2KMmVK0eSoIzvT3X5BXBjVYaaybliRM8DG6fOQzvex0fWRcMXuYv1tMBGiHMp6LwE5+jH3vJZcpG3dFQ5/9e3UCnEDxsdRF/SEcJSnJi9b52yF/KnaSDmEfuV8UwcuLckJkeb28JnElxVFzF8TJn1aJNBjrc1j62926l0T94oJtXs8kJr0OrOV15l2mY5NKa8j/l+fv6NeeYpsvOzlRzw== X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(2980300002)(339900001)(199003)(189002)(189998001)(2351001)(50466002)(50226001)(104016003)(19580395003)(33646002)(48376002)(106466001)(77096005)(77156002)(36756003)(5001920100001)(86362001)(575784001)(6806004)(46102003)(107886002)(229853001)(110136002)(19580405001)(87936001)(50986999)(62966003)(5001960100002)(47776003)(85426001)(105606002)(92566002)(15975445007)(4001430100001)(473944003); DIR:OUT; SFP:1102; SCL:1; SRVR:CY1PR03MB1485; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1485; 2:r9mX/bU1S0bENEFHcsK4ii9ss2irTkgzODvGzMDYsTMieHrjx841pg4/AXN0rCDAuRE6ieHCzAT0J/7P6F+vFn0fe+g8sBrdhvCCMa4rVANibqQvnMfDn+yi7RBp63Tqk1Q5rDg/VSBQtrTAocDmJt9jKBBMO2ObmaONFjquGTs=; 3:Gzpp1bgcG4wnhmYJxcWIJAd05r/ItK2aec29aEUwr4FlUM1hxPmafMav3X9GIIvrECoU8PdN0N2fhWgdzYdeQvmPedXmD+mn1yjCj7IXt2b64k+50zY3GDkjEu6nili6ZtpZD8X74ajDxttm/mlgklRbA/lPrmicHc2D7GMONHwnkdnkpxpb+HYH4zRQDOtmAHIN0BoOQMxmq0q3NNaZnWYOGjezYOmJ+9Nns/Lt3Y4=; 25:H6ANG4PKBesbgL6XYaREK3+DWrA7tHig7ZL2W9fLjMDQTZPYfy7BL7A+8ZHS8TECI20WF8b67jWYrkgYsAYTcWGbLTBqmJ59ae+m1Xu5gkIWNRK4SNTtL4DxY0YuFdSgbOtNrvt2HESCZsTGiiJXOrKPaWTMLOrEmwFZw6NgtKKMuAwV/TpVPn1N38bZJ2rFVDDQbix2QLsdgp7UyNIzyohkCawScZUqpeGVfeGFF0GGZMLC6CIxYdAptW+gW1GO X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR03MB1485; X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1485; 20:m7LvOQe0CL63rcu6+eEKjFbn2w5NnK6ggvKeZ8XKjUwExpWRcSzCnFFWb+F9XWcbTZiKyfapfkNmnE5EsXZ05nfA4arN11VM9i2BwCA7wC7u9Wz3ZSQvOdTvrhCW6LjEu3D5m/Nf/EfpzPI0JmkHk+Km6uMAqgwBLlOcWh/CwrM3SFlMfnMAvxj8npgdjex14z8b8xAZp1kXp1wQD3GxjbuSMphKXmpWO9xcUSf0kHXc1cfzxRMrJ3aDOphvHXYquB/ACRghOnJI2/2PwFGSDQ3hsBbcqad5+qrFoBg724lPrvCRKPLBA2Dm8bTvZWqOiWjnl0cxn6n+FHpFC8f4Rm9HCLvgRoI8jQG0VNguVcQ=; 4:NGOZgGyRhJguh/CcJxVs5iXj/T/yWCaDw3odDfHDwLyCnX+XTUmWbClyUZMfZ51L/J/AhSPaCdcWQsjTX9qt1YZbu13aMQR7XqslyTqPlafeaJU+RDO9EQyaTI/oQN6l7tB6WFPDP0j5YM25yHFtKy3M8AYuEUfW5Y9KkFdsoDZnJuifL5rI4UGC4I6aTOSXXECqNCbQKY/52Jycs9KV/xevL0aU+LQhMfX8cVAt6HJE2RXQNNC+D+Su1AUUCDIP0SgTx7G3bsoBLtYEgO0OrxHYAJ8LkMsvLLww05Eot9Q= CY1PR03MB1485: X-MS-Exchange-Organization-RulesExecuted X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(3002001); SRVR:CY1PR03MB1485; BCL:0; PCL:0; RULEID:; SRVR:CY1PR03MB1485; X-Forefront-PRVS: 0652EA5565 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY1PR03MB1485; 23:rKK4UWuK7e7Wy2n9GXVbOveA+K1EDUmQVG7uC3o4v?= =?us-ascii?Q?g5+AGEJvJ3TWbOuyOFjMTuuvmugIi2KF01wYyudEOFyDCnmksBQtVybbhxAF?= =?us-ascii?Q?bUbO41Y40ezCDOsFQw+eRil5V7wV0uXnzQPEp44Wteau/65tktQOwKCF8vQa?= =?us-ascii?Q?NFpD3ImUsRKzHH2+FRj6+wFNM1BwFkEFhQs/KJVTwrkqnTNYIbG030evtV2b?= =?us-ascii?Q?ssqNANkUhQxqZqe2EzJ105XGabIvfNPU+zzm5eb9cImHxtnxa+7PuabINWmi?= =?us-ascii?Q?v+Q50ymlspnmABXDqUK55pTPy+rJ+maYurdcKfXwzg7vcXZVaIUfEPHTj/a/?= =?us-ascii?Q?14IlXYJNCMteOXNmGh2Fr5F9aKlsXOU6X6mc55ZcQfUpkSfff+PaglMVErIq?= =?us-ascii?Q?b3iPSZP4NNV+mdioN9zWEtGUpuh3xiM2HcemPzei/zexzALIqIXQL+2ye2WF?= =?us-ascii?Q?3qQEN+WY4V97BcJ9bAAK6cQN9dbUj+xFilQ6/fX6hyanSnCJ14unpe0uV/Al?= =?us-ascii?Q?qEARlezuYCml5sOsVhMhPo8ySccgJ9r1VDomREt6A0NQ9c2Btp0Mx83T2qEG?= =?us-ascii?Q?kl59a5Pjm9EM4IgDuSC85yRwoa6/TTip1bxe/TzX162pUfW1FJc8yjOIE8b3?= =?us-ascii?Q?Cbp2xCvuqN95kj/6ka1/L6h5UQfH1KW+egE8thPkUXvwRV3ue50DGekDW1cN?= =?us-ascii?Q?DwNXPP5WPqKv8O9GZ7vDj3OSreAdz6oQeAm4d7bvQyVgKXnRQVQHBOeBml5C?= =?us-ascii?Q?9MPk71jZiJTw+tGaCMzp55MbSopInzlL+P0ZFAFJBplxAWYGwtZ/sm7ToUJN?= =?us-ascii?Q?wRNmqI8OB9ZvdD7hlRGvL6wCFum8ZZVQ9Sd90Sd2V8PpOQfu001KVoNs1RT+?= =?us-ascii?Q?y1OD7zLNChH422WWJ4BqMBCSgrNtxx4TMcHmrjD5OdHrC6epCSEWgoKoRmG2?= =?us-ascii?Q?vvRAGQdDKI6JyLZIlid9YxCNCSaw42r6d/86/A/aHn5krQZLuhPLZQNhlMsN?= =?us-ascii?Q?G4=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR03MB1485; 5:mq6GvPIiAhsiqXyUex0V6LADzbDVgpT3o2BFwSc2Ol2O8XbjV6a+XXVwJYbrTOAhncxczS4XIgyFkLa+lA+PGI91x87u/kmCJanlctBT3AIxOA6JvSGkGYks8KFlKJvj4bb2b4pLKW95xovgb0TLRQ==; 24:L80n+Rui1U5KW8MvurqMfvDPnmZa6rTJtOaQtC29t3IIe3EOvxKOTp2zbnfuNfNFI0rlhXLZVolW79GS6sI77Dk04ofDa7TJH/sa3VgddTg=; 20:La/Ljg4mwSZ8623oSyAhLVkEe22PwSIi9PpLYfzMmca0bxTPE9bngTbM5r8X4O+uWMN8GJ/R5uU8d6uDFOhUkg== X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Jul 2015 06:24:43.9885 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR03MB1485 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: scottwood@freescale.com, hongtao.jia@freescale.com, linuxppc-dev@lists.ozlabs.org, linux-pm@vger.kernel.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" 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. Signed-off-by: Jia Hongtao --- This patch based on: http://patchwork.ozlabs.org/patch/482987/ Changes for V2: * Add tmu-range parse. * Use default trend hook. * Using latest thermal_zone_bind_cooling_device API. * Add calibration check during initialization. * Disable/enalbe device when suspend/resume. drivers/thermal/Kconfig | 11 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 406 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 118938e..a200745 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -180,6 +180,17 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config QORIQ_THERMAL + tristate "Freescale QorIQ Thermal Monitoring Unit" + depends on CPU_THERMAL + depends on OF + default n + help + Enable thermal management based on Freescale QorIQ Thermal Monitoring + Unit (TMU). 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 bool "SPEAr thermal sensor driver" depends on PLAT_SPEAR diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 535dfee..8c25859 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_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..0694f42 --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,406 @@ +/* + * Copyright 2015 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. + * + */ + +/* + * Based on Freescale QorIQ Thermal Monitoring Unit (TMU) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SITES_MAX 16 + +#define TMU_TEMP_PASSIVE 85000 +#define TMU_TEMP_CRITICAL 95000 + +#define TMU_PASSIVE_DELAY 1000 /* Milliseconds */ +#define TMU_POLLING_DELAY 5000 + +/* The driver supports 1 passive trip point and 1 critical trip point */ +enum tmu_thermal_trip { + TMU_TRIP_PASSIVE, + TMU_TRIP_CRITICAL, + TMU_TRIP_NUM, +}; + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + __be32 tritsr; /* Immediate Temperature Site Register */ + __be32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +} __packed; + +struct qoriq_tmu_regs { + __be32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 +#define TMR_MSITE 0x00008000 +#define TMR_ALL (TMR_ME | TMR_ALPF | TMR_MSITE) + __be32 tsr; /* Status Register */ + __be32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x00000007 + u8 res0[0x14]; + __be32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + __be32 tidr; /* Interrupt Detect Register */ + __be32 tiscr; /* Interrupt Site Capture Register */ + __be32 ticscr; /* Interrupt Critical Site Capture Register */ + u8 res1[0x10]; + __be32 tmhtcrh; /* High Temperature Capture Register */ + __be32 tmhtcrl; /* Low Temperature Capture Register */ + u8 res2[0x8]; + __be32 tmhtitr; /* High Temperature Immediate Threshold */ + __be32 tmhtatr; /* High Temperature Average Threshold */ + __be32 tmhtactr; /* High Temperature Average Crit Threshold */ + u8 res3[0x24]; + __be32 ttcfgr; /* Temperature Configuration Register */ + __be32 tscfgr; /* Sensor Configuration Register */ + u8 res4[0x78]; + struct qoriq_tmu_site_regs site[SITES_MAX]; + u8 res5[0x9f8]; + __be32 ipbrr0; /* IP Block Revision Register 0 */ + __be32 ipbrr1; /* IP Block Revision Register 1 */ + u8 res6[0x310]; + __be32 ttr0cr; /* Temperature Range 0 Control Register */ + __be32 ttr1cr; /* Temperature Range 1 Control Register */ + __be32 ttr2cr; /* Temperature Range 2 Control Register */ + __be32 ttr3cr; /* Temperature Range 3 Control Register */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct thermal_cooling_device *cdev; + enum thermal_device_mode mode; + unsigned long temp_passive; + unsigned long temp_critical; + struct qoriq_tmu_regs __iomem *regs; +}; + +static int tmu_get_mode(struct thermal_zone_device *tz, + enum thermal_device_mode *mode) +{ + struct qoriq_tmu_data *data = tz->devdata; + + *mode = data->mode; + + return 0; +} + +static int tmu_set_mode(struct thermal_zone_device *tz, + enum thermal_device_mode mode) +{ + struct qoriq_tmu_data *data = tz->devdata; + + if (mode == THERMAL_DEVICE_ENABLED) { + tz->polling_delay = TMU_POLLING_DELAY; + tz->passive_delay = TMU_PASSIVE_DELAY; + thermal_zone_device_update(tz); + } else { + tz->polling_delay = 0; + tz->passive_delay = 0; + } + + data->mode = mode; + + return 0; +} + +static int tmu_get_temp(struct thermal_zone_device *tz, unsigned long *temp) +{ + u8 val; + struct qoriq_tmu_data *data = tz->devdata; + + val = ioread32be(&data->regs->site[0].tritsr); + *temp = (unsigned long)val * 1000; + + return 0; +} + +static int tmu_get_trip_type(struct thermal_zone_device *tz, int trip, + enum thermal_trip_type *type) +{ + *type = (trip == TMU_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE : + THERMAL_TRIP_CRITICAL; + + return 0; +} + +static int tmu_get_trip_temp(struct thermal_zone_device *tz, int trip, + unsigned long *temp) +{ + struct qoriq_tmu_data *data = tz->devdata; + + *temp = (trip == TMU_TRIP_PASSIVE) ? data->temp_passive : + data->temp_critical; + + return 0; +} + +static int tmu_get_crit_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + struct qoriq_tmu_data *data = tz->devdata; + + *temp = data->temp_critical; + + return 0; +} + +static int tmu_bind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) +{ + int ret; + + ret = thermal_zone_bind_cooling_device(tz, TMU_TRIP_PASSIVE, cdev, + THERMAL_NO_LIMIT, + THERMAL_NO_LIMIT, + THERMAL_WEIGHT_DEFAULT); + if (ret) { + dev_err(&tz->device, + "Binding zone %s with cdev %s failed:%d\n", + tz->type, cdev->type, ret); + } + + return ret; +} + +static int tmu_unbind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) +{ + int ret; + + ret = thermal_zone_unbind_cooling_device(tz, TMU_TRIP_PASSIVE, cdev); + if (ret) { + dev_err(&tz->device, + "Unbinding zone %s with cdev %s failed:%d\n", + tz->type, cdev->type, ret); + } + + return ret; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const __be32 *calibration; + struct device_node *node = pdev->dev.of_node; + struct qoriq_tmu_data *data = dev_get_drvdata(&pdev->dev); + + /* Disable monitoring before calibration */ + iowrite32be(TMR_DISABLE, &data->regs->tmr); + + if (of_property_read_u32_array(node, "fsl,tmu-range", range, 4)) + return -1; + + /* Init temperature range registers */ + iowrite32be(range[0], &data->regs->ttr0cr); + iowrite32be(range[1], &data->regs->ttr1cr); + iowrite32be(range[2], &data->regs->ttr2cr); + iowrite32be(range[3], &data->regs->ttr3cr); + + calibration = of_get_property(node, "fsl,tmu-calibration", &len); + if (calibration == NULL) + return -1; + + for (i = 0; i < len; i += 8, calibration += 2) { + val = (int)of_read_number(calibration, 1); + iowrite32be(val, &data->regs->ttcfgr); + val = (int)of_read_number(calibration + 1, 1); + iowrite32be(val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + iowrite32be(TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + iowrite32be(TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Enable monitoring */ + iowrite32be(TMR_ALL, &data->regs->tmr); +} + +static struct thermal_zone_device_ops tmu_tz_ops = { + .bind = tmu_bind, + .unbind = tmu_unbind, + .get_temp = tmu_get_temp, + .get_mode = tmu_get_mode, + .set_mode = tmu_set_mode, + .get_trip_type = tmu_get_trip_type, + .get_trip_temp = tmu_get_trip_temp, + .get_crit_temp = tmu_get_crit_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + struct cpumask clip_cpus; + struct qoriq_tmu_data *data; + + if (!cpufreq_get_current_driver()) { + dev_dbg(&pdev->dev, "No cpufreq driver yet\n"); + return -EPROBE_DEFER; + } + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -EFAULT; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, data); + data->regs = of_iomap(pdev->dev.of_node, 0); + + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) { + dev_err(&pdev->dev, "TMU calibration failed.\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + cpumask_setall(&clip_cpus); + data->cdev = cpufreq_cooling_register(&clip_cpus); + if (IS_ERR(data->cdev)) { + ret = PTR_ERR(data->cdev); + dev_err(&data->cdev->device, + "Failed to register cpufreq cooling device: %d\n", ret); + goto err_cooling; + } + + data->temp_passive = TMU_TEMP_PASSIVE; + data->temp_critical = TMU_TEMP_CRITICAL; + data->tz = thermal_zone_device_register("tmu_thermal_zone", + TMU_TRIP_NUM, + 0, data, + &tmu_tz_ops, NULL, + TMU_PASSIVE_DELAY, + TMU_POLLING_DELAY); + + 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_thermal; + } + + data->mode = THERMAL_DEVICE_ENABLED; + + return 0; + +err_thermal: + cpufreq_cooling_unregister(data->cdev); + +err_cooling: + iounmap(data->regs); + +err_iomap: + dev_set_drvdata(&pdev->dev, NULL); + devm_kfree(&pdev->dev, data); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = dev_get_drvdata(&pdev->dev); + + /* Disable monitoring */ + iowrite32be(TMR_DISABLE, &data->regs->tmr); + + thermal_zone_device_unregister(data->tz); + cpufreq_cooling_unregister(data->cdev); + iounmap(data->regs); + + dev_set_drvdata(&pdev->dev, NULL); + devm_kfree(&pdev->dev, data); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + iowrite32be(TMR_DISABLE, &data->regs->tmr); + data->mode = THERMAL_DEVICE_DISABLED; + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + iowrite32be(TMR_ALL, &data->regs->tmr); + data->mode = THERMAL_DEVICE_ENABLED; + + 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", }, + {}, +}; + +static struct platform_driver qoriq_tmu = { + .driver = { + .owner = THIS_MODULE, + .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("Freescale QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2");