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 8772ffc28fSDaniel Lezcano #define QRK_DTS_ID_TP_HOT 1 883e8c4d31SAmit Kucheria #define QRK_DTS_SAFE_TP_THRES 105 893e8c4d31SAmit Kucheria 903e8c4d31SAmit Kucheria /* Thermal Sensor Register Lock */ 913e8c4d31SAmit Kucheria #define QRK_DTS_REG_OFFSET_LOCK 0x71 923e8c4d31SAmit Kucheria #define QRK_DTS_LOCK_BIT BIT(5) 933e8c4d31SAmit Kucheria 943e8c4d31SAmit Kucheria /* Quark DTS has 2 trip points: hot & catastrophic */ 953e8c4d31SAmit Kucheria #define QRK_MAX_DTS_TRIPS 2 963e8c4d31SAmit Kucheria 973e8c4d31SAmit Kucheria #define DEFAULT_POLL_DELAY 2000 983e8c4d31SAmit Kucheria 993e8c4d31SAmit Kucheria struct soc_sensor_entry { 1003e8c4d31SAmit Kucheria bool locked; 1013e8c4d31SAmit Kucheria u32 store_ptps; 1023e8c4d31SAmit Kucheria u32 store_dts_enable; 1033e8c4d31SAmit Kucheria struct thermal_zone_device *tzone; 1043e8c4d31SAmit Kucheria }; 1053e8c4d31SAmit Kucheria 1063e8c4d31SAmit Kucheria static struct soc_sensor_entry *soc_dts; 1073e8c4d31SAmit Kucheria 1083e8c4d31SAmit Kucheria static int polling_delay = DEFAULT_POLL_DELAY; 1093e8c4d31SAmit Kucheria module_param(polling_delay, int, 0644); 1103e8c4d31SAmit Kucheria MODULE_PARM_DESC(polling_delay, 1113e8c4d31SAmit Kucheria "Polling interval for checking trip points (in milliseconds)"); 1123e8c4d31SAmit Kucheria 1133e8c4d31SAmit Kucheria static DEFINE_MUTEX(dts_update_mutex); 1143e8c4d31SAmit Kucheria 1153e8c4d31SAmit Kucheria static int soc_dts_enable(struct thermal_zone_device *tzd) 1163e8c4d31SAmit Kucheria { 1173e8c4d31SAmit Kucheria u32 out; 1185f68d078SDaniel Lezcano struct soc_sensor_entry *aux_entry = thermal_zone_device_priv(tzd); 1193e8c4d31SAmit Kucheria int ret; 1203e8c4d31SAmit Kucheria 1213e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1223e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, &out); 1233e8c4d31SAmit Kucheria if (ret) 1243e8c4d31SAmit Kucheria return ret; 1253e8c4d31SAmit Kucheria 1267f4957beSAndrzej Pietrasiewicz if (out & QRK_DTS_ENABLE_BIT) 1273e8c4d31SAmit Kucheria return 0; 1283e8c4d31SAmit Kucheria 1293e8c4d31SAmit Kucheria if (!aux_entry->locked) { 1303e8c4d31SAmit Kucheria out |= QRK_DTS_ENABLE_BIT; 1313e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 1323e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, out); 1333e8c4d31SAmit Kucheria if (ret) 1343e8c4d31SAmit Kucheria return ret; 1353e8c4d31SAmit Kucheria } else { 1363e8c4d31SAmit Kucheria pr_info("DTS is locked. Cannot enable DTS\n"); 1373e8c4d31SAmit Kucheria ret = -EPERM; 1383e8c4d31SAmit Kucheria } 1393e8c4d31SAmit Kucheria 1403e8c4d31SAmit Kucheria return ret; 1413e8c4d31SAmit Kucheria } 1423e8c4d31SAmit Kucheria 1433e8c4d31SAmit Kucheria static int soc_dts_disable(struct thermal_zone_device *tzd) 1443e8c4d31SAmit Kucheria { 1453e8c4d31SAmit Kucheria u32 out; 1465f68d078SDaniel Lezcano struct soc_sensor_entry *aux_entry = thermal_zone_device_priv(tzd); 1473e8c4d31SAmit Kucheria int ret; 1483e8c4d31SAmit Kucheria 1493e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1503e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, &out); 1513e8c4d31SAmit Kucheria if (ret) 1523e8c4d31SAmit Kucheria return ret; 1533e8c4d31SAmit Kucheria 1547f4957beSAndrzej Pietrasiewicz if (!(out & QRK_DTS_ENABLE_BIT)) 1553e8c4d31SAmit Kucheria return 0; 1563e8c4d31SAmit Kucheria 1573e8c4d31SAmit Kucheria if (!aux_entry->locked) { 1583e8c4d31SAmit Kucheria out &= ~QRK_DTS_ENABLE_BIT; 1593e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 1603e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, out); 1613e8c4d31SAmit Kucheria 1623e8c4d31SAmit Kucheria if (ret) 1633e8c4d31SAmit Kucheria return ret; 1643e8c4d31SAmit Kucheria } else { 1653e8c4d31SAmit Kucheria pr_info("DTS is locked. Cannot disable DTS\n"); 1663e8c4d31SAmit Kucheria ret = -EPERM; 1673e8c4d31SAmit Kucheria } 1683e8c4d31SAmit Kucheria 1693e8c4d31SAmit Kucheria return ret; 1703e8c4d31SAmit Kucheria } 1713e8c4d31SAmit Kucheria 17272ffc28fSDaniel Lezcano static int get_trip_temp(int trip) 1733e8c4d31SAmit Kucheria { 17472ffc28fSDaniel Lezcano int status, temp; 1753e8c4d31SAmit Kucheria u32 out; 1763e8c4d31SAmit Kucheria 1773e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 1783e8c4d31SAmit Kucheria status = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 1793e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, &out); 1803e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 1813e8c4d31SAmit Kucheria 1823e8c4d31SAmit Kucheria if (status) 18372ffc28fSDaniel Lezcano return THERMAL_TEMP_INVALID; 1843e8c4d31SAmit Kucheria 1853e8c4d31SAmit Kucheria /* 1863e8c4d31SAmit Kucheria * Thermal Sensor Programmable Trip Point Register has 8-bit 1873e8c4d31SAmit Kucheria * fields for critical (catastrophic) and hot set trip point 1883e8c4d31SAmit Kucheria * thresholds. The threshold value is always offset by its 1893e8c4d31SAmit Kucheria * temperature base (50 degree Celsius). 1903e8c4d31SAmit Kucheria */ 19172ffc28fSDaniel Lezcano temp = (out >> (trip * QRK_DTS_SHIFT_TP)) & QRK_DTS_MASK_TP_THRES; 19272ffc28fSDaniel Lezcano temp -= QRK_DTS_TEMP_BASE; 1933e8c4d31SAmit Kucheria 19472ffc28fSDaniel Lezcano return temp; 1953e8c4d31SAmit Kucheria } 1963e8c4d31SAmit Kucheria 1973e8c4d31SAmit Kucheria static int update_trip_temp(struct soc_sensor_entry *aux_entry, 1983e8c4d31SAmit Kucheria int trip, int temp) 1993e8c4d31SAmit Kucheria { 2003e8c4d31SAmit Kucheria u32 out; 2013e8c4d31SAmit Kucheria u32 temp_out; 2023e8c4d31SAmit Kucheria u32 store_ptps; 2033e8c4d31SAmit Kucheria int ret; 2043e8c4d31SAmit Kucheria 2053e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 2063e8c4d31SAmit Kucheria if (aux_entry->locked) { 2073e8c4d31SAmit Kucheria ret = -EPERM; 2083e8c4d31SAmit Kucheria goto failed; 2093e8c4d31SAmit Kucheria } 2103e8c4d31SAmit Kucheria 2113e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 2123e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, &store_ptps); 2133e8c4d31SAmit Kucheria if (ret) 2143e8c4d31SAmit Kucheria goto failed; 2153e8c4d31SAmit Kucheria 2163e8c4d31SAmit Kucheria /* 2173e8c4d31SAmit Kucheria * Protection against unsafe trip point thresdhold value. 2183e8c4d31SAmit Kucheria * As Quark X1000 data-sheet does not provide any recommendation 2193e8c4d31SAmit Kucheria * regarding the safe trip point threshold value to use, we choose 2203e8c4d31SAmit Kucheria * the safe value according to the threshold value set by UEFI BIOS. 2213e8c4d31SAmit Kucheria */ 2223e8c4d31SAmit Kucheria if (temp > QRK_DTS_SAFE_TP_THRES) 2233e8c4d31SAmit Kucheria temp = QRK_DTS_SAFE_TP_THRES; 2243e8c4d31SAmit Kucheria 2253e8c4d31SAmit Kucheria /* 2263e8c4d31SAmit Kucheria * Thermal Sensor Programmable Trip Point Register has 8-bit 2273e8c4d31SAmit Kucheria * fields for critical (catastrophic) and hot set trip point 2283e8c4d31SAmit Kucheria * thresholds. The threshold value is always offset by its 2293e8c4d31SAmit Kucheria * temperature base (50 degree Celsius). 2303e8c4d31SAmit Kucheria */ 2313e8c4d31SAmit Kucheria temp_out = temp + QRK_DTS_TEMP_BASE; 2323e8c4d31SAmit Kucheria out = (store_ptps & ~(QRK_DTS_MASK_TP_THRES << 2333e8c4d31SAmit Kucheria (trip * QRK_DTS_SHIFT_TP))); 2343e8c4d31SAmit Kucheria out |= (temp_out & QRK_DTS_MASK_TP_THRES) << 2353e8c4d31SAmit Kucheria (trip * QRK_DTS_SHIFT_TP); 2363e8c4d31SAmit Kucheria 2373e8c4d31SAmit Kucheria ret = iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 2383e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, out); 2393e8c4d31SAmit Kucheria 2403e8c4d31SAmit Kucheria failed: 2413e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 2423e8c4d31SAmit Kucheria return ret; 2433e8c4d31SAmit Kucheria } 2443e8c4d31SAmit Kucheria 2453e8c4d31SAmit Kucheria static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 2463e8c4d31SAmit Kucheria int temp) 2473e8c4d31SAmit Kucheria { 2485f68d078SDaniel Lezcano return update_trip_temp(thermal_zone_device_priv(tzd), trip, temp); 2493e8c4d31SAmit Kucheria } 2503e8c4d31SAmit Kucheria 2513e8c4d31SAmit Kucheria static int sys_get_curr_temp(struct thermal_zone_device *tzd, 2523e8c4d31SAmit Kucheria int *temp) 2533e8c4d31SAmit Kucheria { 2543e8c4d31SAmit Kucheria u32 out; 2553e8c4d31SAmit Kucheria int ret; 2563e8c4d31SAmit Kucheria 2573e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 2583e8c4d31SAmit Kucheria ret = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 2593e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_TEMP, &out); 2603e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 2613e8c4d31SAmit Kucheria 2623e8c4d31SAmit Kucheria if (ret) 2633e8c4d31SAmit Kucheria return ret; 2643e8c4d31SAmit Kucheria 2653e8c4d31SAmit Kucheria /* 2663e8c4d31SAmit Kucheria * Thermal Sensor Temperature Register has 8-bit field 2673e8c4d31SAmit Kucheria * for temperature value (offset by temperature base 2683e8c4d31SAmit Kucheria * 50 degree Celsius). 2693e8c4d31SAmit Kucheria */ 2703e8c4d31SAmit Kucheria out = (out >> QRK_DTS_OFFSET_TEMP) & QRK_DTS_MASK_TEMP; 2713e8c4d31SAmit Kucheria *temp = out - QRK_DTS_TEMP_BASE; 2723e8c4d31SAmit Kucheria 2733e8c4d31SAmit Kucheria return 0; 2743e8c4d31SAmit Kucheria } 2753e8c4d31SAmit Kucheria 276f5e50bf4SAndrzej Pietrasiewicz static int sys_change_mode(struct thermal_zone_device *tzd, 2773e8c4d31SAmit Kucheria enum thermal_device_mode mode) 2783e8c4d31SAmit Kucheria { 2793e8c4d31SAmit Kucheria int ret; 2803e8c4d31SAmit Kucheria 2813e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 2823e8c4d31SAmit Kucheria if (mode == THERMAL_DEVICE_ENABLED) 2833e8c4d31SAmit Kucheria ret = soc_dts_enable(tzd); 2843e8c4d31SAmit Kucheria else 2853e8c4d31SAmit Kucheria ret = soc_dts_disable(tzd); 2863e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 2873e8c4d31SAmit Kucheria 2883e8c4d31SAmit Kucheria return ret; 2893e8c4d31SAmit Kucheria } 2903e8c4d31SAmit Kucheria 29162dd1784SRafael J. Wysocki static const struct thermal_zone_device_ops tzone_ops = { 2923e8c4d31SAmit Kucheria .get_temp = sys_get_curr_temp, 2933e8c4d31SAmit Kucheria .set_trip_temp = sys_set_trip_temp, 294f5e50bf4SAndrzej Pietrasiewicz .change_mode = sys_change_mode, 2953e8c4d31SAmit Kucheria }; 2963e8c4d31SAmit Kucheria 2973e8c4d31SAmit Kucheria static void free_soc_dts(struct soc_sensor_entry *aux_entry) 2983e8c4d31SAmit Kucheria { 2993e8c4d31SAmit Kucheria if (aux_entry) { 3003e8c4d31SAmit Kucheria if (!aux_entry->locked) { 3013e8c4d31SAmit Kucheria mutex_lock(&dts_update_mutex); 3023e8c4d31SAmit Kucheria iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 3033e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, 3043e8c4d31SAmit Kucheria aux_entry->store_dts_enable); 3053e8c4d31SAmit Kucheria 3063e8c4d31SAmit Kucheria iosf_mbi_write(QRK_MBI_UNIT_RMU, MBI_REG_WRITE, 3073e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, 3083e8c4d31SAmit Kucheria aux_entry->store_ptps); 3093e8c4d31SAmit Kucheria mutex_unlock(&dts_update_mutex); 3103e8c4d31SAmit Kucheria } 3113e8c4d31SAmit Kucheria thermal_zone_device_unregister(aux_entry->tzone); 3123e8c4d31SAmit Kucheria kfree(aux_entry); 3133e8c4d31SAmit Kucheria } 3143e8c4d31SAmit Kucheria } 3153e8c4d31SAmit Kucheria 3163e8c4d31SAmit Kucheria static struct soc_sensor_entry *alloc_soc_dts(void) 3173e8c4d31SAmit Kucheria { 318fcbf8780SRafael J. Wysocki struct thermal_trip trips[QRK_MAX_DTS_TRIPS] = { 0 }; 3193e8c4d31SAmit Kucheria struct soc_sensor_entry *aux_entry; 3203e8c4d31SAmit Kucheria int err; 3213e8c4d31SAmit Kucheria u32 out; 3223e8c4d31SAmit Kucheria 3233e8c4d31SAmit Kucheria aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 3243e8c4d31SAmit Kucheria if (!aux_entry) { 3253e8c4d31SAmit Kucheria err = -ENOMEM; 3263e8c4d31SAmit Kucheria return ERR_PTR(-ENOMEM); 3273e8c4d31SAmit Kucheria } 3283e8c4d31SAmit Kucheria 3293e8c4d31SAmit Kucheria /* Check if DTS register is locked */ 3303e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3313e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_LOCK, &out); 3323e8c4d31SAmit Kucheria if (err) 3333e8c4d31SAmit Kucheria goto err_ret; 3343e8c4d31SAmit Kucheria 335cca52f69SRafael J. Wysocki aux_entry->locked = !!(out & QRK_DTS_LOCK_BIT); 3363e8c4d31SAmit Kucheria 3373e8c4d31SAmit Kucheria /* Store DTS default state if DTS registers are not locked */ 3383e8c4d31SAmit Kucheria if (!aux_entry->locked) { 3393e8c4d31SAmit Kucheria /* Store DTS default enable for restore on exit */ 3403e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3413e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_ENABLE, 3423e8c4d31SAmit Kucheria &aux_entry->store_dts_enable); 3433e8c4d31SAmit Kucheria if (err) 3443e8c4d31SAmit Kucheria goto err_ret; 3453e8c4d31SAmit Kucheria 3463e8c4d31SAmit Kucheria /* Store DTS default PTPS register for restore on exit */ 3473e8c4d31SAmit Kucheria err = iosf_mbi_read(QRK_MBI_UNIT_RMU, MBI_REG_READ, 3483e8c4d31SAmit Kucheria QRK_DTS_REG_OFFSET_PTPS, 3493e8c4d31SAmit Kucheria &aux_entry->store_ptps); 3503e8c4d31SAmit Kucheria if (err) 3513e8c4d31SAmit Kucheria goto err_ret; 352cca52f69SRafael J. Wysocki 353cca52f69SRafael J. Wysocki trips[QRK_DTS_ID_TP_CRITICAL].flags |= THERMAL_TRIP_FLAG_RW_TEMP; 354cca52f69SRafael J. Wysocki trips[QRK_DTS_ID_TP_HOT].flags |= THERMAL_TRIP_FLAG_RW_TEMP; 3553e8c4d31SAmit Kucheria } 3563e8c4d31SAmit Kucheria 357fcbf8780SRafael J. Wysocki trips[QRK_DTS_ID_TP_CRITICAL].temperature = get_trip_temp(QRK_DTS_ID_TP_CRITICAL); 358fcbf8780SRafael J. Wysocki trips[QRK_DTS_ID_TP_CRITICAL].type = THERMAL_TRIP_CRITICAL; 35972ffc28fSDaniel Lezcano 360fcbf8780SRafael J. Wysocki trips[QRK_DTS_ID_TP_HOT].temperature = get_trip_temp(QRK_DTS_ID_TP_HOT); 361fcbf8780SRafael J. Wysocki trips[QRK_DTS_ID_TP_HOT].type = THERMAL_TRIP_HOT; 36272ffc28fSDaniel Lezcano 36372ffc28fSDaniel Lezcano aux_entry->tzone = thermal_zone_device_register_with_trips("quark_dts", 364fcbf8780SRafael J. Wysocki trips, 3653e8c4d31SAmit Kucheria QRK_MAX_DTS_TRIPS, 366*4a62d588SRafael J. Wysocki aux_entry, 367cca52f69SRafael J. Wysocki &tzone_ops, 36872ffc28fSDaniel Lezcano NULL, 0, polling_delay); 3693e8c4d31SAmit Kucheria if (IS_ERR(aux_entry->tzone)) { 3703e8c4d31SAmit Kucheria err = PTR_ERR(aux_entry->tzone); 3713e8c4d31SAmit Kucheria goto err_ret; 3723e8c4d31SAmit Kucheria } 3733e8c4d31SAmit Kucheria 3747f4957beSAndrzej Pietrasiewicz err = thermal_zone_device_enable(aux_entry->tzone); 3753e8c4d31SAmit Kucheria if (err) 3763e8c4d31SAmit Kucheria goto err_aux_status; 3773e8c4d31SAmit Kucheria 3783e8c4d31SAmit Kucheria return aux_entry; 3793e8c4d31SAmit Kucheria 3803e8c4d31SAmit Kucheria err_aux_status: 3813e8c4d31SAmit Kucheria thermal_zone_device_unregister(aux_entry->tzone); 3823e8c4d31SAmit Kucheria err_ret: 3833e8c4d31SAmit Kucheria kfree(aux_entry); 3843e8c4d31SAmit Kucheria return ERR_PTR(err); 3853e8c4d31SAmit Kucheria } 3863e8c4d31SAmit Kucheria 3873e8c4d31SAmit Kucheria static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { 3889c51044cSThomas Gleixner X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), 3893e8c4d31SAmit Kucheria {} 3903e8c4d31SAmit Kucheria }; 3913e8c4d31SAmit Kucheria MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); 3923e8c4d31SAmit Kucheria 3933e8c4d31SAmit Kucheria static int __init intel_quark_thermal_init(void) 3943e8c4d31SAmit Kucheria { 3953e8c4d31SAmit Kucheria if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) 3963e8c4d31SAmit Kucheria return -ENODEV; 3973e8c4d31SAmit Kucheria 3983e8c4d31SAmit Kucheria soc_dts = alloc_soc_dts(); 399f1b930e7SDan Carpenter if (IS_ERR(soc_dts)) 400f1b930e7SDan Carpenter return PTR_ERR(soc_dts); 4013e8c4d31SAmit Kucheria 4023e8c4d31SAmit Kucheria return 0; 4033e8c4d31SAmit Kucheria } 4043e8c4d31SAmit Kucheria 4053e8c4d31SAmit Kucheria static void __exit intel_quark_thermal_exit(void) 4063e8c4d31SAmit Kucheria { 4073e8c4d31SAmit Kucheria free_soc_dts(soc_dts); 4083e8c4d31SAmit Kucheria } 4093e8c4d31SAmit Kucheria 4103e8c4d31SAmit Kucheria module_init(intel_quark_thermal_init) 4113e8c4d31SAmit Kucheria module_exit(intel_quark_thermal_exit) 4123e8c4d31SAmit Kucheria 4133e8c4d31SAmit Kucheria MODULE_DESCRIPTION("Intel Quark DTS Thermal Driver"); 4143e8c4d31SAmit Kucheria MODULE_AUTHOR("Ong Boon Leong <boon.leong.ong@intel.com>"); 4153e8c4d31SAmit Kucheria MODULE_LICENSE("Dual BSD/GPL"); 416