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: 6889801 X-Patchwork-Delegate: eduardo.valentin@ti.com Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 12F159F380 for ; Wed, 29 Jul 2015 06:58:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6451B20600 for ; Wed, 29 Jul 2015 06:58:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9A4FA204EB for ; Wed, 29 Jul 2015 06:58:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751891AbbG2G6X (ORCPT ); Wed, 29 Jul 2015 02:58:23 -0400 Received: from mail-by2on0147.outbound.protection.outlook.com ([207.46.100.147]:14449 "EHLO na01-by2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751797AbbG2G6V (ORCPT ); Wed, 29 Jul 2015 02:58:21 -0400 X-Greylist: delayed 2015 seconds by postgrey-1.27 at vger.kernel.org; Wed, 29 Jul 2015 02:58:21 EDT 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: CC: , , , 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 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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");