13e8c4d31SAmit Kucheria /* 23e8c4d31SAmit Kucheria * intel_quark_dts_thermal.c 33e8c4d31SAmit Kucheria * 43e8c4d31SAmit Kucheria * This file is provided under a dual BSD/GPLv2 license. When using or 53e8c4d31SAmit Kucheria * redistributing this file, you may do so under either license. 63e8c4d31SAmit Kucheria * 73e8c4d31SAmit Kucheria * GPL LICENSE SUMMARY 83e8c4d31SAmit Kucheria * 93e8c4d31SAmit Kucheria * Copyright(c) 2015 Intel Corporation. 103e8c4d31SAmit Kucheria * 113e8c4d31SAmit Kucheria * This program is free software; you can redistribute it and/or modify 123e8c4d31SAmit Kucheria * it under the terms of version 2 of the GNU General Public License as 133e8c4d31SAmit Kucheria * published by the Free Software Foundation. 143e8c4d31SAmit Kucheria * 153e8c4d31SAmit Kucheria * This program is distributed in the hope that it will be useful, but 163e8c4d31SAmit Kucheria * WITHOUT ANY WARRANTY; without even the implied warranty of 173e8c4d31SAmit Kucheria * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 183e8c4d31SAmit Kucheria * General Public License for more details. 193e8c4d31SAmit Kucheria * 203e8c4d31SAmit Kucheria * Contact Information: 213e8c4d31SAmit Kucheria * Ong Boon Leong <boon.leong.ong@intel.com> 223e8c4d31SAmit Kucheria * Intel Malaysia, Penang 233e8c4d31SAmit Kucheria * 243e8c4d31SAmit Kucheria * BSD LICENSE 253e8c4d31SAmit Kucheria * 263e8c4d31SAmit Kucheria * Copyright(c) 2015 Intel Corporation. 273e8c4d31SAmit Kucheria * 283e8c4d31SAmit Kucheria * Redistribution and use in source and binary forms, with or without 293e8c4d31SAmit Kucheria * modification, are permitted provided that the following conditions 303e8c4d31SAmit Kucheria * are met: 313e8c4d31SAmit Kucheria * 323e8c4d31SAmit Kucheria * * Redistributions of source code must retain the above copyright 333e8c4d31SAmit Kucheria * notice, this list of conditions and the following disclaimer. 343e8c4d31SAmit Kucheria * * Redistributions in binary form must reproduce the above copyright 353e8c4d31SAmit Kucheria * notice, this list of conditions and the following disclaimer in 363e8c4d31SAmit Kucheria * the documentation and/or other materials provided with the 373e8c4d31SAmit Kucheria * distribution. 383e8c4d31SAmit Kucheria * * Neither the name of Intel Corporation nor the names of its 393e8c4d31SAmit Kucheria * contributors may be used to endorse or promote products derived 403e8c4d31SAmit Kucheria * from this software without specific prior written permission. 413e8c4d31SAmit Kucheria * 423e8c4d31SAmit Kucheria * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 433e8c4d31SAmit Kucheria * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 443e8c4d31SAmit Kucheria * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 453e8c4d31SAmit Kucheria * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 463e8c4d31SAmit Kucheria * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 473e8c4d31SAmit Kucheria * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 483e8c4d31SAmit Kucheria * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 493e8c4d31SAmit Kucheria * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 503e8c4d31SAmit Kucheria * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 513e8c4d31SAmit Kucheria * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 523e8c4d31SAmit Kucheria * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 533e8c4d31SAmit Kucheria * 543e8c4d31SAmit Kucheria * Quark DTS thermal driver is implemented by referencing 553e8c4d31SAmit Kucheria * intel_soc_dts_thermal.c. 563e8c4d31SAmit Kucheria */ 573e8c4d31SAmit Kucheria 583e8c4d31SAmit Kucheria #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 593e8c4d31SAmit Kucheria 603e8c4d31SAmit Kucheria #include <linux/module.h> 613e8c4d31SAmit Kucheria #include <linux/slab.h> 623e8c4d31SAmit Kucheria #include <linux/interrupt.h> 633e8c4d31SAmit Kucheria #include <linux/thermal.h> 643e8c4d31SAmit Kucheria #include <asm/cpu_device_id.h> 653e8c4d31SAmit Kucheria #include <asm/iosf_mbi.h> 663e8c4d31SAmit Kucheria 673e8c4d31SAmit Kucheria /* DTS reset is programmed via QRK_MBI_UNIT_SOC */ 683e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_RESET 0x34 693e8c4d31SAmit Kucheria #define QRK_DTS_RESET_BIT BIT(0) 703e8c4d31SAmit Kucheria 713e8c4d31SAmit Kucheria /* DTS enable is programmed via QRK_MBI_UNIT_RMU */ 723e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_ENABLE 0xB0 733e8c4d31SAmit Kucheria #define QRK_DTS_ENABLE_BIT BIT(15) 743e8c4d31SAmit Kucheria 753e8c4d31SAmit Kucheria /* Temperature Register is read via QRK_MBI_UNIT_RMU */ 763e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_TEMP 0xB1 773e8c4d31SAmit Kucheria #define QRK_DTS_MASK_TEMP 0xFF 783e8c4d31SAmit Kucheria #define QRK_DTS_OFFSET_TEMP 0 793e8c4d31SAmit Kucheria #define QRK_DTS_OFFSET_REL_TEMP 16 803e8c4d31SAmit Kucheria #define QRK_DTS_TEMP_BASE 50 813e8c4d31SAmit Kucheria 823e8c4d31SAmit Kucheria /* Programmable Trip Point Register is configured via QRK_MBI_UNIT_RMU */ 833e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_PTPS 0xB2 843e8c4d31SAmit Kucheria #define QRK_DTS_MASK_TP_THRES 0xFF 853e8c4d31SAmit Kucheria #define QRK_DTS_SHIFT_TP 8 863e8c4d31SAmit Kucheria #define QRK_DTS_ID_TP_CRITICAL 0 873e8c4d31SAmit Kucheria #define QRK_DTS_SAFE_TP_THRES 105 883e8c4d31SAmit Kucheria 893e8c4d31SAmit Kucheria /* Thermal Sensor Register Lock */ 903e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_LOCK 0x71 913e8c4d31SAmit Kucheria #define QRK_DTS_LOCK_BIT BIT(5) 923e8c4d31SAmit Kucheria 933e8c4d31SAmit Kucheria /* Quark DTS has 2 trip points: hot & catastrophic */ 943e8c4d31SAmit Kucheria #define QRK_MAX_DTS_TRIPS 2 953e8c4d31SAmit Kucheria /* If DTS not locked, all trip points are configurable */ 963e8c4d31SAmit Kucheria #define QRK_DTS_WR_MASK_SET 0x3 973e8c4d31SAmit Kucheria /* If DTS locked, all trip points are not configurable */ 983e8c4d31SAmit Kucheria #define QRK_DTS_WR_MASK_CLR 0 993e8c4d31SAmit Kucheria 1003e8c4d31SAmit Kucheria #define DEFAULT_POLL_DELAY 2000 1013e8c4d31SAmit Kucheria 1023e8c4d31SAmit Kucheria struct soc_sensor_entry { 1033e8c4d31SAmit Kucheria bool locked; 1043e8c4d31SAmit Kucheria u32 store_ptps; 1053e8c4d31SAmit Kucheria u32 store_dts_enable; 1063e8c4d31SAmit Kucheria struct thermal_zone_device *tzone; 1073e8c4d31SAmit Kucheria }; 1083e8c4d31SAmit Kucheria 1093e8c4d31SAmit Kucheria static struct soc_sensor_entry *soc_dts; 1103e8c4d31SAmit Kucheria 1113e8c4d31SAmit Kucheria static int polling_delay = DEFAULT_POLL_DELAY; 1123e8c4d31SAmit Kucheria module_param(polling_delay, int, 0644); 1133e8c4d31SAmit Kucheria MODULE_PARM_DESC(polling_delay, 1143e8c4d31SAmit Kucheria "Polling interval for checking trip points (in milliseconds)"); 1153e8c4d31SAmit Kucheria 1163e8c4d31SAmit Kucheria static DEFINE_MUTEX(dts_update_mutex); 1173e8c4d31SAmit Kucheria 1183e8c4d31SAmit Kucheria static int soc_dts_enable(struct thermal_zone_device *tzd) 1193e8c4d31SAmit Kucheria { 1203e8c4d31SAmit Kucheria u32 out; 1213e8c4d31SAmit Kucheria struct soc_sensor_entry *aux_entry = tzd->devdata; 1223e8c4d31SAmit Kucheria int ret; 1233e8c4d31SAmit Kucheria 1243e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1253e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, &out); 1263e8c4d31SAmit Kucheria if (ret) 1273e8c4d31SAmit Kucheria return ret; 1283e8c4d31SAmit Kucheria 129*7f4957beSAndrzej Pietrasiewicz if (out & QRK_DTS_ENABLE_BIT) 1303e8c4d31SAmit Kucheria return 0; 1313e8c4d31SAmit Kucheria 1323e8c4d31SAmit Kucheria if (!aux_entry->locked) { 1333e8c4d31SAmit Kucheria out |= QRK_DTS_ENABLE_BIT; 1343e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 1353e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, out); 1363e8c4d31SAmit Kucheria if (ret) 1373e8c4d31SAmit Kucheria return ret; 1383e8c4d31SAmit Kucheria } else { 1393e8c4d31SAmit Kucheria pr_info("DTS is locked. Cannot enable DTS\n"); 1403e8c4d31SAmit Kucheria ret = -EPERM; 1413e8c4d31SAmit Kucheria } 1423e8c4d31SAmit Kucheria 1433e8c4d31SAmit Kucheria return ret; 1443e8c4d31SAmit Kucheria } 1453e8c4d31SAmit Kucheria 1463e8c4d31SAmit Kucheria static int soc_dts_disable(struct thermal_zone_device *tzd) 1473e8c4d31SAmit Kucheria { 1483e8c4d31SAmit Kucheria u32 out; 1493e8c4d31SAmit Kucheria struct soc_sensor_entry *aux_entry = tzd->devdata; 1503e8c4d31SAmit Kucheria int ret; 1513e8c4d31SAmit Kucheria 1523e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1533e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, &out); 1543e8c4d31SAmit Kucheria if (ret) 1553e8c4d31SAmit Kucheria return ret; 1563e8c4d31SAmit Kucheria 157*7f4957beSAndrzej Pietrasiewicz if (!(out & QRK_DTS_ENABLE_BIT)) 1583e8c4d31SAmit Kucheria return 0; 1593e8c4d31SAmit Kucheria 1603e8c4d31SAmit Kucheria if (!aux_entry->locked) { 1613e8c4d31SAmit Kucheria out &= ~QRK_DTS_ENABLE_BIT; 1623e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 1633e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, out); 1643e8c4d31SAmit Kucheria 1653e8c4d31SAmit Kucheria if (ret) 1663e8c4d31SAmit Kucheria return ret; 1673e8c4d31SAmit Kucheria } else { 1683e8c4d31SAmit Kucheria pr_info("DTS is locked. Cannot disable DTS\n"); 1693e8c4d31SAmit Kucheria ret = -EPERM; 1703e8c4d31SAmit Kucheria } 1713e8c4d31SAmit Kucheria 1723e8c4d31SAmit Kucheria return ret; 1733e8c4d31SAmit Kucheria } 1743e8c4d31SAmit Kucheria 1753e8c4d31SAmit Kucheria static int _get_trip_temp(int trip, int *temp) 1763e8c4d31SAmit Kucheria { 1773e8c4d31SAmit Kucheria int status; 1783e8c4d31SAmit Kucheria u32 out; 1793e8c4d31SAmit Kucheria 1803e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 1813e8c4d31SAmit Kucheria status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1823e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, &out); 1833e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 1843e8c4d31SAmit Kucheria 1853e8c4d31SAmit Kucheria if (status) 1863e8c4d31SAmit Kucheria return status; 1873e8c4d31SAmit Kucheria 1883e8c4d31SAmit Kucheria /* 1893e8c4d31SAmit Kucheria * Thermal Sensor Programmable Trip Point Register has 8-bit 1903e8c4d31SAmit Kucheria * fields for critical (catastrophic) and hot set trip point 1913e8c4d31SAmit Kucheria * thresholds. The threshold value is always offset by its 1923e8c4d31SAmit Kucheria * temperature base (50 degree Celsius). 1933e8c4d31SAmit Kucheria */ 1943e8c4d31SAmit Kucheria *temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES; 1953e8c4d31SAmit Kucheria *temp -= QRK_DTS_TEMP_BASE; 1963e8c4d31SAmit Kucheria 1973e8c4d31SAmit Kucheria return 0; 1983e8c4d31SAmit Kucheria } 1993e8c4d31SAmit Kucheria 2003e8c4d31SAmit Kucheria static inline int sys_get_trip_temp(struct thermal_zone_device *tzd, 2013e8c4d31SAmit Kucheria int trip, int *temp) 2023e8c4d31SAmit Kucheria { 2033e8c4d31SAmit Kucheria return _get_trip_temp(trip, temp); 2043e8c4d31SAmit Kucheria } 2053e8c4d31SAmit Kucheria 2063e8c4d31SAmit Kucheria static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp) 2073e8c4d31SAmit Kucheria { 2083e8c4d31SAmit Kucheria return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp); 2093e8c4d31SAmit Kucheria } 2103e8c4d31SAmit Kucheria 2113e8c4d31SAmit Kucheria static int update_trip_temp(struct soc_sensor_entry *aux_entry, 2123e8c4d31SAmit Kucheria int trip, int temp) 2133e8c4d31SAmit Kucheria { 2143e8c4d31SAmit Kucheria u32 out; 2153e8c4d31SAmit Kucheria u32 temp_out; 2163e8c4d31SAmit Kucheria u32 store_ptps; 2173e8c4d31SAmit Kucheria int ret; 2183e8c4d31SAmit Kucheria 2193e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 2203e8c4d31SAmit Kucheria if (aux_entry->locked) { 2213e8c4d31SAmit Kucheria ret = -EPERM; 2223e8c4d31SAmit Kucheria goto failed; 2233e8c4d31SAmit Kucheria } 2243e8c4d31SAmit Kucheria 2253e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 2263e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, &store_ptps); 2273e8c4d31SAmit Kucheria if (ret) 2283e8c4d31SAmit Kucheria goto failed; 2293e8c4d31SAmit Kucheria 2303e8c4d31SAmit Kucheria /* 2313e8c4d31SAmit Kucheria * Protection against unsafe trip point thresdhold value. 2323e8c4d31SAmit Kucheria * As Quark X1000 data-sheet does not provide any recommendation 2333e8c4d31SAmit Kucheria * regarding the safe trip point threshold value to use, we choose 2343e8c4d31SAmit Kucheria * the safe value according to the threshold value set by UEFI BIOS. 2353e8c4d31SAmit Kucheria */ 2363e8c4d31SAmit Kucheria if (temp > QRK_DTS_SAFE_TP_THRES) 2373e8c4d31SAmit Kucheria temp = QRK_DTS_SAFE_TP_THRES; 2383e8c4d31SAmit Kucheria 2393e8c4d31SAmit Kucheria /* 2403e8c4d31SAmit Kucheria * Thermal Sensor Programmable Trip Point Register has 8-bit 2413e8c4d31SAmit Kucheria * fields for critical (catastrophic) and hot set trip point 2423e8c4d31SAmit Kucheria * thresholds. The threshold value is always offset by its 2433e8c4d31SAmit Kucheria * temperature base (50 degree Celsius). 2443e8c4d31SAmit Kucheria */ 2453e8c4d31SAmit Kucheria temp_out = temp + QRK_DTS_TEMP_BASE; 2463e8c4d31SAmit Kucheria out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES << 2473e8c4d31SAmit Kucheria (trip * QRK_DTS_SHIFT_TP))); 2483e8c4d31SAmit Kucheria out |= (temp_out & QRK_DTS_MASK_TP_THRES) << 2493e8c4d31SAmit Kucheria (trip * QRK_DTS_SHIFT_TP); 2503e8c4d31SAmit Kucheria 2513e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 2523e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, out); 2533e8c4d31SAmit Kucheria 2543e8c4d31SAmit Kucheria failed: 2553e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 2563e8c4d31SAmit Kucheria return ret; 2573e8c4d31SAmit Kucheria } 2583e8c4d31SAmit Kucheria 2593e8c4d31SAmit Kucheria static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 2603e8c4d31SAmit Kucheria int temp) 2613e8c4d31SAmit Kucheria { 2623e8c4d31SAmit Kucheria return update_trip_temp(tzd->devdata, trip, temp); 2633e8c4d31SAmit Kucheria } 2643e8c4d31SAmit Kucheria 2653e8c4d31SAmit Kucheria static int sys_get_trip_type(struct thermal_zone_device *thermal, 2663e8c4d31SAmit Kucheria int trip, enum thermal_trip_type *type) 2673e8c4d31SAmit Kucheria { 2683e8c4d31SAmit Kucheria if (trip) 2693e8c4d31SAmit Kucheria *type = THERMAL_TRIP_HOT; 2703e8c4d31SAmit Kucheria else 2713e8c4d31SAmit Kucheria *type = THERMAL_TRIP_CRITICAL; 2723e8c4d31SAmit Kucheria 2733e8c4d31SAmit Kucheria return 0; 2743e8c4d31SAmit Kucheria } 2753e8c4d31SAmit Kucheria 2763e8c4d31SAmit Kucheria static int sys_get_curr_temp(struct thermal_zone_device *tzd, 2773e8c4d31SAmit Kucheria int *temp) 2783e8c4d31SAmit Kucheria { 2793e8c4d31SAmit Kucheria u32 out; 2803e8c4d31SAmit Kucheria int ret; 2813e8c4d31SAmit Kucheria 2823e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 2833e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 2843e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_TEMP, &out); 2853e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 2863e8c4d31SAmit Kucheria 2873e8c4d31SAmit Kucheria if (ret) 2883e8c4d31SAmit Kucheria return ret; 2893e8c4d31SAmit Kucheria 2903e8c4d31SAmit Kucheria /* 2913e8c4d31SAmit Kucheria * Thermal Sensor Temperature Register has 8-bit field 2923e8c4d31SAmit Kucheria * for temperature value (offset by temperature base 2933e8c4d31SAmit Kucheria * 50 degree Celsius). 2943e8c4d31SAmit Kucheria */ 2953e8c4d31SAmit Kucheria out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP; 2963e8c4d31SAmit Kucheria *temp = out - QRK_DTS_TEMP_BASE; 2973e8c4d31SAmit Kucheria 2983e8c4d31SAmit Kucheria return 0; 2993e8c4d31SAmit Kucheria } 3003e8c4d31SAmit Kucheria 3013e8c4d31SAmit Kucheria static int sys_set_mode(struct thermal_zone_device *tzd, 3023e8c4d31SAmit Kucheria enum thermal_device_mode mode) 3033e8c4d31SAmit Kucheria { 3043e8c4d31SAmit Kucheria int ret; 3053e8c4d31SAmit Kucheria 3063e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 3073e8c4d31SAmit Kucheria if (mode == THERMAL_DEVICE_ENABLED) 3083e8c4d31SAmit Kucheria ret = soc_dts_enable(tzd); 3093e8c4d31SAmit Kucheria else 3103e8c4d31SAmit Kucheria ret = soc_dts_disable(tzd); 3113e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 3123e8c4d31SAmit Kucheria 3133e8c4d31SAmit Kucheria return ret; 3143e8c4d31SAmit Kucheria } 3153e8c4d31SAmit Kucheria 3163e8c4d31SAmit Kucheria static struct thermal_zone_device_ops tzone_ops = { 3173e8c4d31SAmit Kucheria .get_temp = sys_get_curr_temp, 3183e8c4d31SAmit Kucheria .get_trip_temp = sys_get_trip_temp, 3193e8c4d31SAmit Kucheria .get_trip_type = sys_get_trip_type, 3203e8c4d31SAmit Kucheria .set_trip_temp = sys_set_trip_temp, 3213e8c4d31SAmit Kucheria .get_crit_temp = sys_get_crit_temp, 3223e8c4d31SAmit Kucheria .set_mode = sys_set_mode, 3233e8c4d31SAmit Kucheria }; 3243e8c4d31SAmit Kucheria 3253e8c4d31SAmit Kucheria static void free_soc_dts(struct soc_sensor_entry *aux_entry) 3263e8c4d31SAmit Kucheria { 3273e8c4d31SAmit Kucheria if (aux_entry) { 3283e8c4d31SAmit Kucheria if (!aux_entry->locked) { 3293e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 3303e8c4d31SAmit Kucheria iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 3313e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, 3323e8c4d31SAmit Kucheria aux_entry->store_dts_enable); 3333e8c4d31SAmit Kucheria 3343e8c4d31SAmit Kucheria iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 3353e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, 3363e8c4d31SAmit Kucheria aux_entry->store_ptps); 3373e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 3383e8c4d31SAmit Kucheria } 3393e8c4d31SAmit Kucheria thermal_zone_device_unregister(aux_entry->tzone); 3403e8c4d31SAmit Kucheria kfree(aux_entry); 3413e8c4d31SAmit Kucheria } 3423e8c4d31SAmit Kucheria } 3433e8c4d31SAmit Kucheria 3443e8c4d31SAmit Kucheria static struct soc_sensor_entry *alloc_soc_dts(void) 3453e8c4d31SAmit Kucheria { 3463e8c4d31SAmit Kucheria struct soc_sensor_entry *aux_entry; 3473e8c4d31SAmit Kucheria int err; 3483e8c4d31SAmit Kucheria u32 out; 3493e8c4d31SAmit Kucheria int wr_mask; 3503e8c4d31SAmit Kucheria 3513e8c4d31SAmit Kucheria aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 3523e8c4d31SAmit Kucheria if (!aux_entry) { 3533e8c4d31SAmit Kucheria err = -ENOMEM; 3543e8c4d31SAmit Kucheria return ERR_PTR(-ENOMEM); 3553e8c4d31SAmit Kucheria } 3563e8c4d31SAmit Kucheria 3573e8c4d31SAmit Kucheria /* Check if DTS register is locked */ 3583e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3593e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_LOCK, &out); 3603e8c4d31SAmit Kucheria if (err) 3613e8c4d31SAmit Kucheria goto err_ret; 3623e8c4d31SAmit Kucheria 3633e8c4d31SAmit Kucheria if (out & QRK_DTS_LOCK_BIT) { 3643e8c4d31SAmit Kucheria aux_entry->locked = true; 3653e8c4d31SAmit Kucheria wr_mask = QRK_DTS_WR_MASK_CLR; 3663e8c4d31SAmit Kucheria } else { 3673e8c4d31SAmit Kucheria aux_entry->locked = false; 3683e8c4d31SAmit Kucheria wr_mask = QRK_DTS_WR_MASK_SET; 3693e8c4d31SAmit Kucheria } 3703e8c4d31SAmit Kucheria 3713e8c4d31SAmit Kucheria /* Store DTS default state if DTS registers are not locked */ 3723e8c4d31SAmit Kucheria if (!aux_entry->locked) { 3733e8c4d31SAmit Kucheria /* Store DTS default enable for restore on exit */ 3743e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3753e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, 3763e8c4d31SAmit Kucheria &aux_entry->store_dts_enable); 3773e8c4d31SAmit Kucheria if (err) 3783e8c4d31SAmit Kucheria goto err_ret; 3793e8c4d31SAmit Kucheria 3803e8c4d31SAmit Kucheria /* Store DTS default PTPS register for restore on exit */ 3813e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3823e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, 3833e8c4d31SAmit Kucheria &aux_entry->store_ptps); 3843e8c4d31SAmit Kucheria if (err) 3853e8c4d31SAmit Kucheria goto err_ret; 3863e8c4d31SAmit Kucheria } 3873e8c4d31SAmit Kucheria 3883e8c4d31SAmit Kucheria aux_entry->tzone = thermal_zone_device_register("quark_dts", 3893e8c4d31SAmit Kucheria QRK_MAX_DTS_TRIPS, 3903e8c4d31SAmit Kucheria wr_mask, 3913e8c4d31SAmit Kucheria aux_entry, &tzone_ops, NULL, 0, polling_delay); 3923e8c4d31SAmit Kucheria if (IS_ERR(aux_entry->tzone)) { 3933e8c4d31SAmit Kucheria err = PTR_ERR(aux_entry->tzone); 3943e8c4d31SAmit Kucheria goto err_ret; 3953e8c4d31SAmit Kucheria } 3963e8c4d31SAmit Kucheria 397*7f4957beSAndrzej Pietrasiewicz err = thermal_zone_device_enable(aux_entry->tzone); 3983e8c4d31SAmit Kucheria if (err) 3993e8c4d31SAmit Kucheria goto err_aux_status; 4003e8c4d31SAmit Kucheria 4013e8c4d31SAmit Kucheria return aux_entry; 4023e8c4d31SAmit Kucheria 4033e8c4d31SAmit Kucheria err_aux_status: 4043e8c4d31SAmit Kucheria thermal_zone_device_unregister(aux_entry->tzone); 4053e8c4d31SAmit Kucheria err_ret: 4063e8c4d31SAmit Kucheria kfree(aux_entry); 4073e8c4d31SAmit Kucheria return ERR_PTR(err); 4083e8c4d31SAmit Kucheria } 4093e8c4d31SAmit Kucheria 4103e8c4d31SAmit Kucheria static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { 4119c51044cSThomas Gleixner X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), 4123e8c4d31SAmit Kucheria {} 4133e8c4d31SAmit Kucheria }; 4143e8c4d31SAmit Kucheria MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); 4153e8c4d31SAmit Kucheria 4163e8c4d31SAmit Kucheria static int __init intel_quark_thermal_init(void) 4173e8c4d31SAmit Kucheria { 4183e8c4d31SAmit Kucheria int err = 0; 4193e8c4d31SAmit Kucheria 4203e8c4d31SAmit Kucheria if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) 4213e8c4d31SAmit Kucheria return -ENODEV; 4223e8c4d31SAmit Kucheria 4233e8c4d31SAmit Kucheria soc_dts = alloc_soc_dts(); 4243e8c4d31SAmit Kucheria if (IS_ERR(soc_dts)) { 4253e8c4d31SAmit Kucheria err = PTR_ERR(soc_dts); 4263e8c4d31SAmit Kucheria goto err_free; 4273e8c4d31SAmit Kucheria } 4283e8c4d31SAmit Kucheria 4293e8c4d31SAmit Kucheria return 0; 4303e8c4d31SAmit Kucheria 4313e8c4d31SAmit Kucheria err_free: 4323e8c4d31SAmit Kucheria free_soc_dts(soc_dts); 4333e8c4d31SAmit Kucheria return err; 4343e8c4d31SAmit Kucheria } 4353e8c4d31SAmit Kucheria 4363e8c4d31SAmit Kucheria static void __exit intel_quark_thermal_exit(void) 4373e8c4d31SAmit Kucheria { 4383e8c4d31SAmit Kucheria free_soc_dts(soc_dts); 4393e8c4d31SAmit Kucheria } 4403e8c4d31SAmit Kucheria 4413e8c4d31SAmit Kucheria module_init(intel_quark_thermal_init) 4423e8c4d31SAmit Kucheria module_exit(intel_quark_thermal_exit) 4433e8c4d31SAmit Kucheria 4443e8c4d31SAmit Kucheria MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver"); 4453e8c4d31SAmit Kucheria MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>"); 4463e8c4d31SAmit Kucheria MODULE_LICENSE("Dual BSD/GPL"); 447