1cbac8f63SCaesar Wang /* 2cbac8f63SCaesar Wang * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 3cbac8f63SCaesar Wang * 420f0af75SCaesar Wang * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd 520f0af75SCaesar Wang * Caesar Wang <wxt@rock-chips.com> 620f0af75SCaesar Wang * 7cbac8f63SCaesar Wang * This program is free software; you can redistribute it and/or modify it 8cbac8f63SCaesar Wang * under the terms and conditions of the GNU General Public License, 9cbac8f63SCaesar Wang * version 2, as published by the Free Software Foundation. 10cbac8f63SCaesar Wang * 11cbac8f63SCaesar Wang * This program is distributed in the hope it will be useful, but WITHOUT 12cbac8f63SCaesar Wang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13cbac8f63SCaesar Wang * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14cbac8f63SCaesar Wang * more details. 15cbac8f63SCaesar Wang */ 16cbac8f63SCaesar Wang 17cbac8f63SCaesar Wang #include <linux/clk.h> 18cbac8f63SCaesar Wang #include <linux/delay.h> 19cbac8f63SCaesar Wang #include <linux/interrupt.h> 20cbac8f63SCaesar Wang #include <linux/io.h> 21cbac8f63SCaesar Wang #include <linux/module.h> 22cbac8f63SCaesar Wang #include <linux/of.h> 23cbac8f63SCaesar Wang #include <linux/of_address.h> 24cbac8f63SCaesar Wang #include <linux/of_irq.h> 25cbac8f63SCaesar Wang #include <linux/platform_device.h> 26cbac8f63SCaesar Wang #include <linux/reset.h> 27cbac8f63SCaesar Wang #include <linux/thermal.h> 28c970872eSCaesar Wang #include <linux/pinctrl/consumer.h> 29cbac8f63SCaesar Wang 30cbac8f63SCaesar Wang /** 31cbac8f63SCaesar Wang * If the temperature over a period of time High, 32cbac8f63SCaesar Wang * the resulting TSHUT gave CRU module,let it reset the entire chip, 33cbac8f63SCaesar Wang * or via GPIO give PMIC. 34cbac8f63SCaesar Wang */ 35cbac8f63SCaesar Wang enum tshut_mode { 36cbac8f63SCaesar Wang TSHUT_MODE_CRU = 0, 37cbac8f63SCaesar Wang TSHUT_MODE_GPIO, 38cbac8f63SCaesar Wang }; 39cbac8f63SCaesar Wang 40cbac8f63SCaesar Wang /** 4113c1cfdaSCaesar Wang * The system Temperature Sensors tshut(tshut) polarity 42cbac8f63SCaesar Wang * the bit 8 is tshut polarity. 43cbac8f63SCaesar Wang * 0: low active, 1: high active 44cbac8f63SCaesar Wang */ 45cbac8f63SCaesar Wang enum tshut_polarity { 46cbac8f63SCaesar Wang TSHUT_LOW_ACTIVE = 0, 47cbac8f63SCaesar Wang TSHUT_HIGH_ACTIVE, 48cbac8f63SCaesar Wang }; 49cbac8f63SCaesar Wang 50cbac8f63SCaesar Wang /** 511d98b618SCaesar Wang * The system has two Temperature Sensors. 521d98b618SCaesar Wang * sensor0 is for CPU, and sensor1 is for GPU. 53cbac8f63SCaesar Wang */ 54cbac8f63SCaesar Wang enum sensor_id { 551d98b618SCaesar Wang SENSOR_CPU = 0, 56cbac8f63SCaesar Wang SENSOR_GPU, 57cbac8f63SCaesar Wang }; 58cbac8f63SCaesar Wang 591d98b618SCaesar Wang /** 60020ba95dSCaesar Wang * The conversion table has the adc value and temperature. 6113c1cfdaSCaesar Wang * ADC_DECREMENT: the adc value is of diminishing.(e.g. v2_code_table) 6213c1cfdaSCaesar Wang * ADC_INCREMENT: the adc value is incremental.(e.g. v3_code_table) 63020ba95dSCaesar Wang */ 64020ba95dSCaesar Wang enum adc_sort_mode { 65020ba95dSCaesar Wang ADC_DECREMENT = 0, 66020ba95dSCaesar Wang ADC_INCREMENT, 67020ba95dSCaesar Wang }; 68020ba95dSCaesar Wang 69020ba95dSCaesar Wang /** 701d98b618SCaesar Wang * The max sensors is two in rockchip SoCs. 711d98b618SCaesar Wang * Two sensors: CPU and GPU sensor. 721d98b618SCaesar Wang */ 731d98b618SCaesar Wang #define SOC_MAX_SENSORS 2 741d98b618SCaesar Wang 7513c1cfdaSCaesar Wang /** 7613c1cfdaSCaesar Wang * struct chip_tsadc_table: hold information about chip-specific differences 7713c1cfdaSCaesar Wang * @id: conversion table 7813c1cfdaSCaesar Wang * @length: size of conversion table 7913c1cfdaSCaesar Wang * @data_mask: mask to apply on data inputs 8013c1cfdaSCaesar Wang * @mode: sort mode of this adc variant (incrementing or decrementing) 8113c1cfdaSCaesar Wang */ 82ce74110dSCaesar Wang struct chip_tsadc_table { 83ce74110dSCaesar Wang const struct tsadc_table *id; 84ce74110dSCaesar Wang unsigned int length; 85ce74110dSCaesar Wang u32 data_mask; 86020ba95dSCaesar Wang enum adc_sort_mode mode; 87ce74110dSCaesar Wang }; 88ce74110dSCaesar Wang 89cbac8f63SCaesar Wang struct rockchip_tsadc_chip { 901d98b618SCaesar Wang /* The sensor id of chip correspond to the ADC channel */ 911d98b618SCaesar Wang int chn_id[SOC_MAX_SENSORS]; 921d98b618SCaesar Wang int chn_num; 931d98b618SCaesar Wang 94cbac8f63SCaesar Wang /* The hardware-controlled tshut property */ 95437df217SCaesar Wang int tshut_temp; 96cbac8f63SCaesar Wang enum tshut_mode tshut_mode; 97cbac8f63SCaesar Wang enum tshut_polarity tshut_polarity; 98cbac8f63SCaesar Wang 99cbac8f63SCaesar Wang /* Chip-wide methods */ 100cbac8f63SCaesar Wang void (*initialize)(void __iomem *reg, enum tshut_polarity p); 101cbac8f63SCaesar Wang void (*irq_ack)(void __iomem *reg); 102cbac8f63SCaesar Wang void (*control)(void __iomem *reg, bool on); 103cbac8f63SCaesar Wang 104cbac8f63SCaesar Wang /* Per-sensor methods */ 105ce74110dSCaesar Wang int (*get_temp)(struct chip_tsadc_table table, 106ce74110dSCaesar Wang int chn, void __iomem *reg, int *temp); 107ce74110dSCaesar Wang void (*set_tshut_temp)(struct chip_tsadc_table table, 108437df217SCaesar Wang int chn, void __iomem *reg, int temp); 109cbac8f63SCaesar Wang void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); 110ce74110dSCaesar Wang 111ce74110dSCaesar Wang /* Per-table methods */ 112ce74110dSCaesar Wang struct chip_tsadc_table table; 113cbac8f63SCaesar Wang }; 114cbac8f63SCaesar Wang 115cbac8f63SCaesar Wang struct rockchip_thermal_sensor { 116cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal; 117cbac8f63SCaesar Wang struct thermal_zone_device *tzd; 1181d98b618SCaesar Wang int id; 119cbac8f63SCaesar Wang }; 120cbac8f63SCaesar Wang 121cbac8f63SCaesar Wang struct rockchip_thermal_data { 122cbac8f63SCaesar Wang const struct rockchip_tsadc_chip *chip; 123cbac8f63SCaesar Wang struct platform_device *pdev; 124cbac8f63SCaesar Wang struct reset_control *reset; 125cbac8f63SCaesar Wang 1261d98b618SCaesar Wang struct rockchip_thermal_sensor sensors[SOC_MAX_SENSORS]; 127cbac8f63SCaesar Wang 128cbac8f63SCaesar Wang struct clk *clk; 129cbac8f63SCaesar Wang struct clk *pclk; 130cbac8f63SCaesar Wang 131cbac8f63SCaesar Wang void __iomem *regs; 132cbac8f63SCaesar Wang 133437df217SCaesar Wang int tshut_temp; 134cbac8f63SCaesar Wang enum tshut_mode tshut_mode; 135cbac8f63SCaesar Wang enum tshut_polarity tshut_polarity; 136cbac8f63SCaesar Wang }; 137cbac8f63SCaesar Wang 1381d98b618SCaesar Wang /* TSADC Sensor info define: */ 139cbac8f63SCaesar Wang #define TSADCV2_AUTO_CON 0x04 140cbac8f63SCaesar Wang #define TSADCV2_INT_EN 0x08 141cbac8f63SCaesar Wang #define TSADCV2_INT_PD 0x0c 142cbac8f63SCaesar Wang #define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) 143cbac8f63SCaesar Wang #define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) 144cbac8f63SCaesar Wang #define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 145cbac8f63SCaesar Wang #define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 146cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD 0x68 147cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_HT 0x6c 148cbac8f63SCaesar Wang 149cbac8f63SCaesar Wang #define TSADCV2_AUTO_EN BIT(0) 150cbac8f63SCaesar Wang #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) 151cbac8f63SCaesar Wang #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) 152cbac8f63SCaesar Wang 153cbac8f63SCaesar Wang #define TSADCV2_INT_SRC_EN(chn) BIT(chn) 154cbac8f63SCaesar Wang #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) 155cbac8f63SCaesar Wang #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) 156cbac8f63SCaesar Wang 1577b02a5e7SCaesar Wang #define TSADCV1_INT_PD_CLEAR_MASK ~BIT(16) 158452e01b3SDmitry Torokhov #define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) 159cbac8f63SCaesar Wang 160cbac8f63SCaesar Wang #define TSADCV2_DATA_MASK 0xfff 16120f0af75SCaesar Wang #define TSADCV3_DATA_MASK 0x3ff 16220f0af75SCaesar Wang 163cbac8f63SCaesar Wang #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 164cbac8f63SCaesar Wang #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 165cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ 166cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ 167cbac8f63SCaesar Wang 168cbac8f63SCaesar Wang struct tsadc_table { 169d9a241cbSDmitry Torokhov u32 code; 170437df217SCaesar Wang int temp; 171cbac8f63SCaesar Wang }; 172cbac8f63SCaesar Wang 1737b02a5e7SCaesar Wang /** 1747b02a5e7SCaesar Wang * Note: 1757b02a5e7SCaesar Wang * Code to Temperature mapping of the Temperature sensor is a piece wise linear 1767b02a5e7SCaesar Wang * curve.Any temperature, code faling between to 2 give temperatures can be 1777b02a5e7SCaesar Wang * linearly interpolated. 1787b02a5e7SCaesar Wang * Code to Temperature mapping should be updated based on sillcon results. 1797b02a5e7SCaesar Wang */ 1807b02a5e7SCaesar Wang static const struct tsadc_table v1_code_table[] = { 1817b02a5e7SCaesar Wang {TSADCV3_DATA_MASK, -40000}, 1827b02a5e7SCaesar Wang {436, -40000}, 1837b02a5e7SCaesar Wang {431, -35000}, 1847b02a5e7SCaesar Wang {426, -30000}, 1857b02a5e7SCaesar Wang {421, -25000}, 1867b02a5e7SCaesar Wang {416, -20000}, 1877b02a5e7SCaesar Wang {411, -15000}, 1887b02a5e7SCaesar Wang {406, -10000}, 1897b02a5e7SCaesar Wang {401, -5000}, 1907b02a5e7SCaesar Wang {395, 0}, 1917b02a5e7SCaesar Wang {390, 5000}, 1927b02a5e7SCaesar Wang {385, 10000}, 1937b02a5e7SCaesar Wang {380, 15000}, 1947b02a5e7SCaesar Wang {375, 20000}, 1957b02a5e7SCaesar Wang {370, 25000}, 1967b02a5e7SCaesar Wang {364, 30000}, 1977b02a5e7SCaesar Wang {359, 35000}, 1987b02a5e7SCaesar Wang {354, 40000}, 1997b02a5e7SCaesar Wang {349, 45000}, 2007b02a5e7SCaesar Wang {343, 50000}, 2017b02a5e7SCaesar Wang {338, 55000}, 2027b02a5e7SCaesar Wang {333, 60000}, 2037b02a5e7SCaesar Wang {328, 65000}, 2047b02a5e7SCaesar Wang {322, 70000}, 2057b02a5e7SCaesar Wang {317, 75000}, 2067b02a5e7SCaesar Wang {312, 80000}, 2077b02a5e7SCaesar Wang {307, 85000}, 2087b02a5e7SCaesar Wang {301, 90000}, 2097b02a5e7SCaesar Wang {296, 95000}, 2107b02a5e7SCaesar Wang {291, 100000}, 2117b02a5e7SCaesar Wang {286, 105000}, 2127b02a5e7SCaesar Wang {280, 110000}, 2137b02a5e7SCaesar Wang {275, 115000}, 2147b02a5e7SCaesar Wang {270, 120000}, 2157b02a5e7SCaesar Wang {264, 125000}, 2167b02a5e7SCaesar Wang }; 2177b02a5e7SCaesar Wang 218cbac8f63SCaesar Wang static const struct tsadc_table v2_code_table[] = { 219cbac8f63SCaesar Wang {TSADCV2_DATA_MASK, -40000}, 220cbac8f63SCaesar Wang {3800, -40000}, 221cbac8f63SCaesar Wang {3792, -35000}, 222cbac8f63SCaesar Wang {3783, -30000}, 223cbac8f63SCaesar Wang {3774, -25000}, 224cbac8f63SCaesar Wang {3765, -20000}, 225cbac8f63SCaesar Wang {3756, -15000}, 226cbac8f63SCaesar Wang {3747, -10000}, 227cbac8f63SCaesar Wang {3737, -5000}, 228cbac8f63SCaesar Wang {3728, 0}, 229cbac8f63SCaesar Wang {3718, 5000}, 230cbac8f63SCaesar Wang {3708, 10000}, 231cbac8f63SCaesar Wang {3698, 15000}, 232cbac8f63SCaesar Wang {3688, 20000}, 233cbac8f63SCaesar Wang {3678, 25000}, 234cbac8f63SCaesar Wang {3667, 30000}, 235cbac8f63SCaesar Wang {3656, 35000}, 236cbac8f63SCaesar Wang {3645, 40000}, 237cbac8f63SCaesar Wang {3634, 45000}, 238cbac8f63SCaesar Wang {3623, 50000}, 239cbac8f63SCaesar Wang {3611, 55000}, 240cbac8f63SCaesar Wang {3600, 60000}, 241cbac8f63SCaesar Wang {3588, 65000}, 242cbac8f63SCaesar Wang {3575, 70000}, 243cbac8f63SCaesar Wang {3563, 75000}, 244cbac8f63SCaesar Wang {3550, 80000}, 245cbac8f63SCaesar Wang {3537, 85000}, 246cbac8f63SCaesar Wang {3524, 90000}, 247cbac8f63SCaesar Wang {3510, 95000}, 248cbac8f63SCaesar Wang {3496, 100000}, 249cbac8f63SCaesar Wang {3482, 105000}, 250cbac8f63SCaesar Wang {3467, 110000}, 251cbac8f63SCaesar Wang {3452, 115000}, 252cbac8f63SCaesar Wang {3437, 120000}, 253cbac8f63SCaesar Wang {3421, 125000}, 254cbac8f63SCaesar Wang }; 255cbac8f63SCaesar Wang 25620f0af75SCaesar Wang static const struct tsadc_table v3_code_table[] = { 25720f0af75SCaesar Wang {0, -40000}, 25820f0af75SCaesar Wang {106, -40000}, 25920f0af75SCaesar Wang {108, -35000}, 26020f0af75SCaesar Wang {110, -30000}, 26120f0af75SCaesar Wang {112, -25000}, 26220f0af75SCaesar Wang {114, -20000}, 26320f0af75SCaesar Wang {116, -15000}, 26420f0af75SCaesar Wang {118, -10000}, 26520f0af75SCaesar Wang {120, -5000}, 26620f0af75SCaesar Wang {122, 0}, 26720f0af75SCaesar Wang {124, 5000}, 26820f0af75SCaesar Wang {126, 10000}, 26920f0af75SCaesar Wang {128, 15000}, 27020f0af75SCaesar Wang {130, 20000}, 27120f0af75SCaesar Wang {132, 25000}, 27220f0af75SCaesar Wang {134, 30000}, 27320f0af75SCaesar Wang {136, 35000}, 27420f0af75SCaesar Wang {138, 40000}, 27520f0af75SCaesar Wang {140, 45000}, 27620f0af75SCaesar Wang {142, 50000}, 27720f0af75SCaesar Wang {144, 55000}, 27820f0af75SCaesar Wang {146, 60000}, 27920f0af75SCaesar Wang {148, 65000}, 28020f0af75SCaesar Wang {150, 70000}, 28120f0af75SCaesar Wang {152, 75000}, 28220f0af75SCaesar Wang {154, 80000}, 28320f0af75SCaesar Wang {156, 85000}, 28420f0af75SCaesar Wang {158, 90000}, 28520f0af75SCaesar Wang {160, 95000}, 28620f0af75SCaesar Wang {162, 100000}, 28720f0af75SCaesar Wang {163, 105000}, 28820f0af75SCaesar Wang {165, 110000}, 28920f0af75SCaesar Wang {167, 115000}, 29020f0af75SCaesar Wang {169, 120000}, 29120f0af75SCaesar Wang {171, 125000}, 29220f0af75SCaesar Wang {TSADCV3_DATA_MASK, 125000}, 29320f0af75SCaesar Wang }; 29420f0af75SCaesar Wang 295b0d70338SCaesar Wang static const struct tsadc_table v4_code_table[] = { 296b0d70338SCaesar Wang {TSADCV3_DATA_MASK, -40000}, 297b0d70338SCaesar Wang {431, -40000}, 298b0d70338SCaesar Wang {426, -35000}, 299b0d70338SCaesar Wang {421, -30000}, 300b0d70338SCaesar Wang {415, -25000}, 301b0d70338SCaesar Wang {410, -20000}, 302b0d70338SCaesar Wang {405, -15000}, 303b0d70338SCaesar Wang {399, -10000}, 304b0d70338SCaesar Wang {394, -5000}, 305b0d70338SCaesar Wang {389, 0}, 306b0d70338SCaesar Wang {383, 5000}, 307b0d70338SCaesar Wang {378, 10000}, 308b0d70338SCaesar Wang {373, 15000}, 309b0d70338SCaesar Wang {367, 20000}, 310b0d70338SCaesar Wang {362, 25000}, 311b0d70338SCaesar Wang {357, 30000}, 312b0d70338SCaesar Wang {351, 35000}, 313b0d70338SCaesar Wang {346, 40000}, 314b0d70338SCaesar Wang {340, 45000}, 315b0d70338SCaesar Wang {335, 50000}, 316b0d70338SCaesar Wang {330, 55000}, 317b0d70338SCaesar Wang {324, 60000}, 318b0d70338SCaesar Wang {319, 65000}, 319b0d70338SCaesar Wang {313, 70000}, 320b0d70338SCaesar Wang {308, 75000}, 321b0d70338SCaesar Wang {302, 80000}, 322b0d70338SCaesar Wang {297, 85000}, 323b0d70338SCaesar Wang {291, 90000}, 324b0d70338SCaesar Wang {286, 95000}, 325b0d70338SCaesar Wang {281, 100000}, 326b0d70338SCaesar Wang {275, 105000}, 327b0d70338SCaesar Wang {270, 110000}, 328b0d70338SCaesar Wang {264, 115000}, 329b0d70338SCaesar Wang {259, 120000}, 330b0d70338SCaesar Wang {253, 125000}, 331b0d70338SCaesar Wang }; 332b0d70338SCaesar Wang 333ce74110dSCaesar Wang static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, 334437df217SCaesar Wang int temp) 335cbac8f63SCaesar Wang { 336cbac8f63SCaesar Wang int high, low, mid; 337cbac8f63SCaesar Wang 338cbac8f63SCaesar Wang low = 0; 339ce74110dSCaesar Wang high = table.length - 1; 340cbac8f63SCaesar Wang mid = (high + low) / 2; 341cbac8f63SCaesar Wang 342ce74110dSCaesar Wang if (temp < table.id[low].temp || temp > table.id[high].temp) 343cbac8f63SCaesar Wang return 0; 344cbac8f63SCaesar Wang 345cbac8f63SCaesar Wang while (low <= high) { 346ce74110dSCaesar Wang if (temp == table.id[mid].temp) 347ce74110dSCaesar Wang return table.id[mid].code; 348ce74110dSCaesar Wang else if (temp < table.id[mid].temp) 349cbac8f63SCaesar Wang high = mid - 1; 350cbac8f63SCaesar Wang else 351cbac8f63SCaesar Wang low = mid + 1; 352cbac8f63SCaesar Wang mid = (low + high) / 2; 353cbac8f63SCaesar Wang } 354cbac8f63SCaesar Wang 355cbac8f63SCaesar Wang return 0; 356cbac8f63SCaesar Wang } 357cbac8f63SCaesar Wang 358ce74110dSCaesar Wang static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, 359ce74110dSCaesar Wang int *temp) 360cbac8f63SCaesar Wang { 361d9a241cbSDmitry Torokhov unsigned int low = 1; 362ce74110dSCaesar Wang unsigned int high = table.length - 1; 3631e9a1aeaSCaesar Wang unsigned int mid = (low + high) / 2; 3641e9a1aeaSCaesar Wang unsigned int num; 3651e9a1aeaSCaesar Wang unsigned long denom; 366cbac8f63SCaesar Wang 367ce74110dSCaesar Wang WARN_ON(table.length < 2); 368cbac8f63SCaesar Wang 369020ba95dSCaesar Wang switch (table.mode) { 370020ba95dSCaesar Wang case ADC_DECREMENT: 371ce74110dSCaesar Wang code &= table.data_mask; 372ce74110dSCaesar Wang if (code < table.id[high].code) 373d9a241cbSDmitry Torokhov return -EAGAIN; /* Incorrect reading */ 374d9a241cbSDmitry Torokhov 375d9a241cbSDmitry Torokhov while (low <= high) { 376ce74110dSCaesar Wang if (code >= table.id[mid].code && 377ce74110dSCaesar Wang code < table.id[mid - 1].code) 3781e9a1aeaSCaesar Wang break; 379ce74110dSCaesar Wang else if (code < table.id[mid].code) 380cbac8f63SCaesar Wang low = mid + 1; 381cbac8f63SCaesar Wang else 382cbac8f63SCaesar Wang high = mid - 1; 383020ba95dSCaesar Wang 384cbac8f63SCaesar Wang mid = (low + high) / 2; 385cbac8f63SCaesar Wang } 386020ba95dSCaesar Wang break; 387020ba95dSCaesar Wang case ADC_INCREMENT: 388020ba95dSCaesar Wang code &= table.data_mask; 389020ba95dSCaesar Wang if (code < table.id[low].code) 390020ba95dSCaesar Wang return -EAGAIN; /* Incorrect reading */ 391020ba95dSCaesar Wang 392020ba95dSCaesar Wang while (low <= high) { 393020ba95dSCaesar Wang if (code >= table.id[mid - 1].code && 394020ba95dSCaesar Wang code < table.id[mid].code) 395020ba95dSCaesar Wang break; 396020ba95dSCaesar Wang else if (code > table.id[mid].code) 397020ba95dSCaesar Wang low = mid + 1; 398020ba95dSCaesar Wang else 399020ba95dSCaesar Wang high = mid - 1; 400020ba95dSCaesar Wang 401020ba95dSCaesar Wang mid = (low + high) / 2; 402020ba95dSCaesar Wang } 403020ba95dSCaesar Wang break; 404020ba95dSCaesar Wang default: 405020ba95dSCaesar Wang pr_err("Invalid the conversion table\n"); 406020ba95dSCaesar Wang } 407cbac8f63SCaesar Wang 4081e9a1aeaSCaesar Wang /* 4091e9a1aeaSCaesar Wang * The 5C granularity provided by the table is too much. Let's 4101e9a1aeaSCaesar Wang * assume that the relationship between sensor readings and 4111e9a1aeaSCaesar Wang * temperature between 2 table entries is linear and interpolate 4121e9a1aeaSCaesar Wang * to produce less granular result. 4131e9a1aeaSCaesar Wang */ 414ce74110dSCaesar Wang num = table.id[mid].temp - v2_code_table[mid - 1].temp; 415020ba95dSCaesar Wang num *= abs(table.id[mid - 1].code - code); 416020ba95dSCaesar Wang denom = abs(table.id[mid - 1].code - table.id[mid].code); 417ce74110dSCaesar Wang *temp = table.id[mid - 1].temp + (num / denom); 418d9a241cbSDmitry Torokhov 419d9a241cbSDmitry Torokhov return 0; 420cbac8f63SCaesar Wang } 421cbac8f63SCaesar Wang 422cbac8f63SCaesar Wang /** 423144c5565SCaesar Wang * rk_tsadcv2_initialize - initialize TASDC Controller. 424144c5565SCaesar Wang * 425144c5565SCaesar Wang * (1) Set TSADC_V2_AUTO_PERIOD: 426144c5565SCaesar Wang * Configure the interleave between every two accessing of 427144c5565SCaesar Wang * TSADC in normal operation. 428144c5565SCaesar Wang * 429144c5565SCaesar Wang * (2) Set TSADCV2_AUTO_PERIOD_HT: 430144c5565SCaesar Wang * Configure the interleave between every two accessing of 431144c5565SCaesar Wang * TSADC after the temperature is higher than COM_SHUT or COM_INT. 432144c5565SCaesar Wang * 433144c5565SCaesar Wang * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: 434144c5565SCaesar Wang * If the temperature is higher than COMP_INT or COMP_SHUT for 435cbac8f63SCaesar Wang * "debounce" times, TSADC controller will generate interrupt or TSHUT. 436cbac8f63SCaesar Wang */ 437cbac8f63SCaesar Wang static void rk_tsadcv2_initialize(void __iomem *regs, 438cbac8f63SCaesar Wang enum tshut_polarity tshut_polarity) 439cbac8f63SCaesar Wang { 440cbac8f63SCaesar Wang if (tshut_polarity == TSHUT_HIGH_ACTIVE) 441452e01b3SDmitry Torokhov writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, 442cbac8f63SCaesar Wang regs + TSADCV2_AUTO_CON); 443cbac8f63SCaesar Wang else 444452e01b3SDmitry Torokhov writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, 445cbac8f63SCaesar Wang regs + TSADCV2_AUTO_CON); 446cbac8f63SCaesar Wang 447cbac8f63SCaesar Wang writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); 448cbac8f63SCaesar Wang writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, 449cbac8f63SCaesar Wang regs + TSADCV2_HIGHT_INT_DEBOUNCE); 450cbac8f63SCaesar Wang writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, 451cbac8f63SCaesar Wang regs + TSADCV2_AUTO_PERIOD_HT); 452cbac8f63SCaesar Wang writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, 453cbac8f63SCaesar Wang regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); 454cbac8f63SCaesar Wang } 455cbac8f63SCaesar Wang 4567b02a5e7SCaesar Wang static void rk_tsadcv1_irq_ack(void __iomem *regs) 4577b02a5e7SCaesar Wang { 4587b02a5e7SCaesar Wang u32 val; 4597b02a5e7SCaesar Wang 4607b02a5e7SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_PD); 4617b02a5e7SCaesar Wang writel_relaxed(val & TSADCV1_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); 4627b02a5e7SCaesar Wang } 4637b02a5e7SCaesar Wang 464cbac8f63SCaesar Wang static void rk_tsadcv2_irq_ack(void __iomem *regs) 465cbac8f63SCaesar Wang { 466cbac8f63SCaesar Wang u32 val; 467cbac8f63SCaesar Wang 468cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_PD); 469452e01b3SDmitry Torokhov writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); 470cbac8f63SCaesar Wang } 471cbac8f63SCaesar Wang 472cbac8f63SCaesar Wang static void rk_tsadcv2_control(void __iomem *regs, bool enable) 473cbac8f63SCaesar Wang { 474cbac8f63SCaesar Wang u32 val; 475cbac8f63SCaesar Wang 476cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_AUTO_CON); 477cbac8f63SCaesar Wang if (enable) 478cbac8f63SCaesar Wang val |= TSADCV2_AUTO_EN; 479cbac8f63SCaesar Wang else 480cbac8f63SCaesar Wang val &= ~TSADCV2_AUTO_EN; 481cbac8f63SCaesar Wang 482cbac8f63SCaesar Wang writel_relaxed(val, regs + TSADCV2_AUTO_CON); 483cbac8f63SCaesar Wang } 484cbac8f63SCaesar Wang 485ce74110dSCaesar Wang static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, 486ce74110dSCaesar Wang int chn, void __iomem *regs, int *temp) 487cbac8f63SCaesar Wang { 488cbac8f63SCaesar Wang u32 val; 489cbac8f63SCaesar Wang 490cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_DATA(chn)); 491cbac8f63SCaesar Wang 492ce74110dSCaesar Wang return rk_tsadcv2_code_to_temp(table, val, temp); 493cbac8f63SCaesar Wang } 494cbac8f63SCaesar Wang 495ce74110dSCaesar Wang static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, 496437df217SCaesar Wang int chn, void __iomem *regs, int temp) 497cbac8f63SCaesar Wang { 498cbac8f63SCaesar Wang u32 tshut_value, val; 499cbac8f63SCaesar Wang 500ce74110dSCaesar Wang tshut_value = rk_tsadcv2_temp_to_code(table, temp); 501cbac8f63SCaesar Wang writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); 502cbac8f63SCaesar Wang 503cbac8f63SCaesar Wang /* TSHUT will be valid */ 504cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_AUTO_CON); 505cbac8f63SCaesar Wang writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON); 506cbac8f63SCaesar Wang } 507cbac8f63SCaesar Wang 508cbac8f63SCaesar Wang static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, 509cbac8f63SCaesar Wang enum tshut_mode mode) 510cbac8f63SCaesar Wang { 511cbac8f63SCaesar Wang u32 val; 512cbac8f63SCaesar Wang 513cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_EN); 514cbac8f63SCaesar Wang if (mode == TSHUT_MODE_GPIO) { 515cbac8f63SCaesar Wang val &= ~TSADCV2_SHUT_2CRU_SRC_EN(chn); 516cbac8f63SCaesar Wang val |= TSADCV2_SHUT_2GPIO_SRC_EN(chn); 517cbac8f63SCaesar Wang } else { 518cbac8f63SCaesar Wang val &= ~TSADCV2_SHUT_2GPIO_SRC_EN(chn); 519cbac8f63SCaesar Wang val |= TSADCV2_SHUT_2CRU_SRC_EN(chn); 520cbac8f63SCaesar Wang } 521cbac8f63SCaesar Wang 522cbac8f63SCaesar Wang writel_relaxed(val, regs + TSADCV2_INT_EN); 523cbac8f63SCaesar Wang } 524cbac8f63SCaesar Wang 5257b02a5e7SCaesar Wang static const struct rockchip_tsadc_chip rk3228_tsadc_data = { 5267b02a5e7SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 5277b02a5e7SCaesar Wang .chn_num = 1, /* one channel for tsadc */ 5287b02a5e7SCaesar Wang 5297b02a5e7SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 5307b02a5e7SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 5317b02a5e7SCaesar Wang .tshut_temp = 95000, 5327b02a5e7SCaesar Wang 5337b02a5e7SCaesar Wang .initialize = rk_tsadcv2_initialize, 5347b02a5e7SCaesar Wang .irq_ack = rk_tsadcv1_irq_ack, 5357b02a5e7SCaesar Wang .control = rk_tsadcv2_control, 5367b02a5e7SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 5377b02a5e7SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 5387b02a5e7SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 5397b02a5e7SCaesar Wang 5407b02a5e7SCaesar Wang .table = { 5417b02a5e7SCaesar Wang .id = v1_code_table, 5427b02a5e7SCaesar Wang .length = ARRAY_SIZE(v1_code_table), 5437b02a5e7SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 5447b02a5e7SCaesar Wang .mode = ADC_DECREMENT, 5457b02a5e7SCaesar Wang }, 5467b02a5e7SCaesar Wang }; 5477b02a5e7SCaesar Wang 548cbac8f63SCaesar Wang static const struct rockchip_tsadc_chip rk3288_tsadc_data = { 5491d98b618SCaesar Wang .chn_id[SENSOR_CPU] = 1, /* cpu sensor is channel 1 */ 5501d98b618SCaesar Wang .chn_id[SENSOR_GPU] = 2, /* gpu sensor is channel 2 */ 5511d98b618SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 5521d98b618SCaesar Wang 553cbac8f63SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 554cbac8f63SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 555cbac8f63SCaesar Wang .tshut_temp = 95000, 556cbac8f63SCaesar Wang 557cbac8f63SCaesar Wang .initialize = rk_tsadcv2_initialize, 558cbac8f63SCaesar Wang .irq_ack = rk_tsadcv2_irq_ack, 559cbac8f63SCaesar Wang .control = rk_tsadcv2_control, 560cbac8f63SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 561cbac8f63SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 562cbac8f63SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 563ce74110dSCaesar Wang 564ce74110dSCaesar Wang .table = { 565ce74110dSCaesar Wang .id = v2_code_table, 566ce74110dSCaesar Wang .length = ARRAY_SIZE(v2_code_table), 567ce74110dSCaesar Wang .data_mask = TSADCV2_DATA_MASK, 568020ba95dSCaesar Wang .mode = ADC_DECREMENT, 569ce74110dSCaesar Wang }, 570cbac8f63SCaesar Wang }; 571cbac8f63SCaesar Wang 57220f0af75SCaesar Wang static const struct rockchip_tsadc_chip rk3368_tsadc_data = { 57320f0af75SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 57420f0af75SCaesar Wang .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ 57520f0af75SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 57620f0af75SCaesar Wang 57720f0af75SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 57820f0af75SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 57920f0af75SCaesar Wang .tshut_temp = 95000, 58020f0af75SCaesar Wang 58120f0af75SCaesar Wang .initialize = rk_tsadcv2_initialize, 58220f0af75SCaesar Wang .irq_ack = rk_tsadcv2_irq_ack, 58320f0af75SCaesar Wang .control = rk_tsadcv2_control, 58420f0af75SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 58520f0af75SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 58620f0af75SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 58720f0af75SCaesar Wang 58820f0af75SCaesar Wang .table = { 58920f0af75SCaesar Wang .id = v3_code_table, 59020f0af75SCaesar Wang .length = ARRAY_SIZE(v3_code_table), 59120f0af75SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 59220f0af75SCaesar Wang .mode = ADC_INCREMENT, 59320f0af75SCaesar Wang }, 59420f0af75SCaesar Wang }; 59520f0af75SCaesar Wang 596b0d70338SCaesar Wang static const struct rockchip_tsadc_chip rk3399_tsadc_data = { 597b0d70338SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 598b0d70338SCaesar Wang .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ 599b0d70338SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 600b0d70338SCaesar Wang 601b0d70338SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 602b0d70338SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 603b0d70338SCaesar Wang .tshut_temp = 95000, 604b0d70338SCaesar Wang 605b0d70338SCaesar Wang .initialize = rk_tsadcv2_initialize, 606b0d70338SCaesar Wang .irq_ack = rk_tsadcv1_irq_ack, 607b0d70338SCaesar Wang .control = rk_tsadcv2_control, 608b0d70338SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 609b0d70338SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 610b0d70338SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 611b0d70338SCaesar Wang 612b0d70338SCaesar Wang .table = { 613b0d70338SCaesar Wang .id = v4_code_table, 614b0d70338SCaesar Wang .length = ARRAY_SIZE(v4_code_table), 615b0d70338SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 616b0d70338SCaesar Wang .mode = ADC_DECREMENT, 617b0d70338SCaesar Wang }, 618b0d70338SCaesar Wang }; 619b0d70338SCaesar Wang 620cbac8f63SCaesar Wang static const struct of_device_id of_rockchip_thermal_match[] = { 621cbac8f63SCaesar Wang { 6227b02a5e7SCaesar Wang .compatible = "rockchip,rk3228-tsadc", 6237b02a5e7SCaesar Wang .data = (void *)&rk3228_tsadc_data, 6247b02a5e7SCaesar Wang }, 6257b02a5e7SCaesar Wang { 626cbac8f63SCaesar Wang .compatible = "rockchip,rk3288-tsadc", 627cbac8f63SCaesar Wang .data = (void *)&rk3288_tsadc_data, 628cbac8f63SCaesar Wang }, 62920f0af75SCaesar Wang { 63020f0af75SCaesar Wang .compatible = "rockchip,rk3368-tsadc", 63120f0af75SCaesar Wang .data = (void *)&rk3368_tsadc_data, 63220f0af75SCaesar Wang }, 633b0d70338SCaesar Wang { 634b0d70338SCaesar Wang .compatible = "rockchip,rk3399-tsadc", 635b0d70338SCaesar Wang .data = (void *)&rk3399_tsadc_data, 636b0d70338SCaesar Wang }, 637cbac8f63SCaesar Wang { /* end */ }, 638cbac8f63SCaesar Wang }; 639cbac8f63SCaesar Wang MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); 640cbac8f63SCaesar Wang 641cbac8f63SCaesar Wang static void 642cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on) 643cbac8f63SCaesar Wang { 644cbac8f63SCaesar Wang struct thermal_zone_device *tzd = sensor->tzd; 645cbac8f63SCaesar Wang 646cbac8f63SCaesar Wang tzd->ops->set_mode(tzd, 647cbac8f63SCaesar Wang on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); 648cbac8f63SCaesar Wang } 649cbac8f63SCaesar Wang 650cbac8f63SCaesar Wang static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) 651cbac8f63SCaesar Wang { 652cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = dev; 653cbac8f63SCaesar Wang int i; 654cbac8f63SCaesar Wang 655cbac8f63SCaesar Wang dev_dbg(&thermal->pdev->dev, "thermal alarm\n"); 656cbac8f63SCaesar Wang 657cbac8f63SCaesar Wang thermal->chip->irq_ack(thermal->regs); 658cbac8f63SCaesar Wang 6591d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 660cbac8f63SCaesar Wang thermal_zone_device_update(thermal->sensors[i].tzd); 661cbac8f63SCaesar Wang 662cbac8f63SCaesar Wang return IRQ_HANDLED; 663cbac8f63SCaesar Wang } 664cbac8f63SCaesar Wang 66517e8351aSSascha Hauer static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) 666cbac8f63SCaesar Wang { 667cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor = _sensor; 668cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = sensor->thermal; 669cbac8f63SCaesar Wang const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip; 670cbac8f63SCaesar Wang int retval; 671cbac8f63SCaesar Wang 672ce74110dSCaesar Wang retval = tsadc->get_temp(tsadc->table, 673ce74110dSCaesar Wang sensor->id, thermal->regs, out_temp); 67417e8351aSSascha Hauer dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n", 675cbac8f63SCaesar Wang sensor->id, *out_temp, retval); 676cbac8f63SCaesar Wang 677cbac8f63SCaesar Wang return retval; 678cbac8f63SCaesar Wang } 679cbac8f63SCaesar Wang 680cbac8f63SCaesar Wang static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = { 681cbac8f63SCaesar Wang .get_temp = rockchip_thermal_get_temp, 682cbac8f63SCaesar Wang }; 683cbac8f63SCaesar Wang 684cbac8f63SCaesar Wang static int rockchip_configure_from_dt(struct device *dev, 685cbac8f63SCaesar Wang struct device_node *np, 686cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal) 687cbac8f63SCaesar Wang { 688cbac8f63SCaesar Wang u32 shut_temp, tshut_mode, tshut_polarity; 689cbac8f63SCaesar Wang 690cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) { 691cbac8f63SCaesar Wang dev_warn(dev, 692437df217SCaesar Wang "Missing tshut temp property, using default %d\n", 693cbac8f63SCaesar Wang thermal->chip->tshut_temp); 694cbac8f63SCaesar Wang thermal->tshut_temp = thermal->chip->tshut_temp; 695cbac8f63SCaesar Wang } else { 696cbac8f63SCaesar Wang thermal->tshut_temp = shut_temp; 697cbac8f63SCaesar Wang } 698cbac8f63SCaesar Wang 699cbac8f63SCaesar Wang if (thermal->tshut_temp > INT_MAX) { 700437df217SCaesar Wang dev_err(dev, "Invalid tshut temperature specified: %d\n", 701cbac8f63SCaesar Wang thermal->tshut_temp); 702cbac8f63SCaesar Wang return -ERANGE; 703cbac8f63SCaesar Wang } 704cbac8f63SCaesar Wang 705cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) { 706cbac8f63SCaesar Wang dev_warn(dev, 707cbac8f63SCaesar Wang "Missing tshut mode property, using default (%s)\n", 708cbac8f63SCaesar Wang thermal->chip->tshut_mode == TSHUT_MODE_GPIO ? 709cbac8f63SCaesar Wang "gpio" : "cru"); 710cbac8f63SCaesar Wang thermal->tshut_mode = thermal->chip->tshut_mode; 711cbac8f63SCaesar Wang } else { 712cbac8f63SCaesar Wang thermal->tshut_mode = tshut_mode; 713cbac8f63SCaesar Wang } 714cbac8f63SCaesar Wang 715cbac8f63SCaesar Wang if (thermal->tshut_mode > 1) { 716cbac8f63SCaesar Wang dev_err(dev, "Invalid tshut mode specified: %d\n", 717cbac8f63SCaesar Wang thermal->tshut_mode); 718cbac8f63SCaesar Wang return -EINVAL; 719cbac8f63SCaesar Wang } 720cbac8f63SCaesar Wang 721cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-polarity", 722cbac8f63SCaesar Wang &tshut_polarity)) { 723cbac8f63SCaesar Wang dev_warn(dev, 724cbac8f63SCaesar Wang "Missing tshut-polarity property, using default (%s)\n", 725cbac8f63SCaesar Wang thermal->chip->tshut_polarity == TSHUT_LOW_ACTIVE ? 726cbac8f63SCaesar Wang "low" : "high"); 727cbac8f63SCaesar Wang thermal->tshut_polarity = thermal->chip->tshut_polarity; 728cbac8f63SCaesar Wang } else { 729cbac8f63SCaesar Wang thermal->tshut_polarity = tshut_polarity; 730cbac8f63SCaesar Wang } 731cbac8f63SCaesar Wang 732cbac8f63SCaesar Wang if (thermal->tshut_polarity > 1) { 733cbac8f63SCaesar Wang dev_err(dev, "Invalid tshut-polarity specified: %d\n", 734cbac8f63SCaesar Wang thermal->tshut_polarity); 735cbac8f63SCaesar Wang return -EINVAL; 736cbac8f63SCaesar Wang } 737cbac8f63SCaesar Wang 738cbac8f63SCaesar Wang return 0; 739cbac8f63SCaesar Wang } 740cbac8f63SCaesar Wang 741cbac8f63SCaesar Wang static int 742cbac8f63SCaesar Wang rockchip_thermal_register_sensor(struct platform_device *pdev, 743cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal, 744cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor, 7451d98b618SCaesar Wang int id) 746cbac8f63SCaesar Wang { 747cbac8f63SCaesar Wang const struct rockchip_tsadc_chip *tsadc = thermal->chip; 748cbac8f63SCaesar Wang int error; 749cbac8f63SCaesar Wang 750cbac8f63SCaesar Wang tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); 751ce74110dSCaesar Wang tsadc->set_tshut_temp(tsadc->table, id, thermal->regs, 752ce74110dSCaesar Wang thermal->tshut_temp); 753cbac8f63SCaesar Wang 754cbac8f63SCaesar Wang sensor->thermal = thermal; 755cbac8f63SCaesar Wang sensor->id = id; 756cbac8f63SCaesar Wang sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor, 757cbac8f63SCaesar Wang &rockchip_of_thermal_ops); 758cbac8f63SCaesar Wang if (IS_ERR(sensor->tzd)) { 759cbac8f63SCaesar Wang error = PTR_ERR(sensor->tzd); 760cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to register sensor %d: %d\n", 761cbac8f63SCaesar Wang id, error); 762cbac8f63SCaesar Wang return error; 763cbac8f63SCaesar Wang } 764cbac8f63SCaesar Wang 765cbac8f63SCaesar Wang return 0; 766cbac8f63SCaesar Wang } 767cbac8f63SCaesar Wang 76813c1cfdaSCaesar Wang /** 769cbac8f63SCaesar Wang * Reset TSADC Controller, reset all tsadc registers. 770cbac8f63SCaesar Wang */ 771cbac8f63SCaesar Wang static void rockchip_thermal_reset_controller(struct reset_control *reset) 772cbac8f63SCaesar Wang { 773cbac8f63SCaesar Wang reset_control_assert(reset); 774cbac8f63SCaesar Wang usleep_range(10, 20); 775cbac8f63SCaesar Wang reset_control_deassert(reset); 776cbac8f63SCaesar Wang } 777cbac8f63SCaesar Wang 778cbac8f63SCaesar Wang static int rockchip_thermal_probe(struct platform_device *pdev) 779cbac8f63SCaesar Wang { 780cbac8f63SCaesar Wang struct device_node *np = pdev->dev.of_node; 781cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal; 782cbac8f63SCaesar Wang const struct of_device_id *match; 783cbac8f63SCaesar Wang struct resource *res; 784cbac8f63SCaesar Wang int irq; 7851d98b618SCaesar Wang int i, j; 786cbac8f63SCaesar Wang int error; 787cbac8f63SCaesar Wang 788cbac8f63SCaesar Wang match = of_match_node(of_rockchip_thermal_match, np); 789cbac8f63SCaesar Wang if (!match) 790cbac8f63SCaesar Wang return -ENXIO; 791cbac8f63SCaesar Wang 792cbac8f63SCaesar Wang irq = platform_get_irq(pdev, 0); 793cbac8f63SCaesar Wang if (irq < 0) { 794cbac8f63SCaesar Wang dev_err(&pdev->dev, "no irq resource?\n"); 795cbac8f63SCaesar Wang return -EINVAL; 796cbac8f63SCaesar Wang } 797cbac8f63SCaesar Wang 798cbac8f63SCaesar Wang thermal = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data), 799cbac8f63SCaesar Wang GFP_KERNEL); 800cbac8f63SCaesar Wang if (!thermal) 801cbac8f63SCaesar Wang return -ENOMEM; 802cbac8f63SCaesar Wang 803cbac8f63SCaesar Wang thermal->pdev = pdev; 804cbac8f63SCaesar Wang 805cbac8f63SCaesar Wang thermal->chip = (const struct rockchip_tsadc_chip *)match->data; 806cbac8f63SCaesar Wang if (!thermal->chip) 807cbac8f63SCaesar Wang return -EINVAL; 808cbac8f63SCaesar Wang 809cbac8f63SCaesar Wang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 810cbac8f63SCaesar Wang thermal->regs = devm_ioremap_resource(&pdev->dev, res); 811cbac8f63SCaesar Wang if (IS_ERR(thermal->regs)) 812cbac8f63SCaesar Wang return PTR_ERR(thermal->regs); 813cbac8f63SCaesar Wang 814cbac8f63SCaesar Wang thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb"); 815cbac8f63SCaesar Wang if (IS_ERR(thermal->reset)) { 816cbac8f63SCaesar Wang error = PTR_ERR(thermal->reset); 817cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error); 818cbac8f63SCaesar Wang return error; 819cbac8f63SCaesar Wang } 820cbac8f63SCaesar Wang 821cbac8f63SCaesar Wang thermal->clk = devm_clk_get(&pdev->dev, "tsadc"); 822cbac8f63SCaesar Wang if (IS_ERR(thermal->clk)) { 823cbac8f63SCaesar Wang error = PTR_ERR(thermal->clk); 824cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get tsadc clock: %d\n", error); 825cbac8f63SCaesar Wang return error; 826cbac8f63SCaesar Wang } 827cbac8f63SCaesar Wang 828cbac8f63SCaesar Wang thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 829cbac8f63SCaesar Wang if (IS_ERR(thermal->pclk)) { 8300d0a2bf6SDan Carpenter error = PTR_ERR(thermal->pclk); 831cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n", 832cbac8f63SCaesar Wang error); 833cbac8f63SCaesar Wang return error; 834cbac8f63SCaesar Wang } 835cbac8f63SCaesar Wang 836cbac8f63SCaesar Wang error = clk_prepare_enable(thermal->clk); 837cbac8f63SCaesar Wang if (error) { 838cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to enable converter clock: %d\n", 839cbac8f63SCaesar Wang error); 840cbac8f63SCaesar Wang return error; 841cbac8f63SCaesar Wang } 842cbac8f63SCaesar Wang 843cbac8f63SCaesar Wang error = clk_prepare_enable(thermal->pclk); 844cbac8f63SCaesar Wang if (error) { 845cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to enable pclk: %d\n", error); 846cbac8f63SCaesar Wang goto err_disable_clk; 847cbac8f63SCaesar Wang } 848cbac8f63SCaesar Wang 849cbac8f63SCaesar Wang rockchip_thermal_reset_controller(thermal->reset); 850cbac8f63SCaesar Wang 851cbac8f63SCaesar Wang error = rockchip_configure_from_dt(&pdev->dev, np, thermal); 852cbac8f63SCaesar Wang if (error) { 853cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to parse device tree data: %d\n", 854cbac8f63SCaesar Wang error); 855cbac8f63SCaesar Wang goto err_disable_pclk; 856cbac8f63SCaesar Wang } 857cbac8f63SCaesar Wang 858cbac8f63SCaesar Wang thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 859cbac8f63SCaesar Wang 8601d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 861cbac8f63SCaesar Wang error = rockchip_thermal_register_sensor(pdev, thermal, 8621d98b618SCaesar Wang &thermal->sensors[i], 8631d98b618SCaesar Wang thermal->chip->chn_id[i]); 864cbac8f63SCaesar Wang if (error) { 865cbac8f63SCaesar Wang dev_err(&pdev->dev, 8661d98b618SCaesar Wang "failed to register sensor[%d] : error = %d\n", 8671d98b618SCaesar Wang i, error); 8681d98b618SCaesar Wang for (j = 0; j < i; j++) 8691d98b618SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, 8701d98b618SCaesar Wang thermal->sensors[j].tzd); 871cbac8f63SCaesar Wang goto err_disable_pclk; 872cbac8f63SCaesar Wang } 873cbac8f63SCaesar Wang } 874cbac8f63SCaesar Wang 875cbac8f63SCaesar Wang error = devm_request_threaded_irq(&pdev->dev, irq, NULL, 876cbac8f63SCaesar Wang &rockchip_thermal_alarm_irq_thread, 877cbac8f63SCaesar Wang IRQF_ONESHOT, 878cbac8f63SCaesar Wang "rockchip_thermal", thermal); 879cbac8f63SCaesar Wang if (error) { 880cbac8f63SCaesar Wang dev_err(&pdev->dev, 881cbac8f63SCaesar Wang "failed to request tsadc irq: %d\n", error); 8821d98b618SCaesar Wang goto err_unregister_sensor; 883cbac8f63SCaesar Wang } 884cbac8f63SCaesar Wang 885cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, true); 886cbac8f63SCaesar Wang 8871d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 888cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 889cbac8f63SCaesar Wang 890cbac8f63SCaesar Wang platform_set_drvdata(pdev, thermal); 891cbac8f63SCaesar Wang 892cbac8f63SCaesar Wang return 0; 893cbac8f63SCaesar Wang 8941d98b618SCaesar Wang err_unregister_sensor: 8951d98b618SCaesar Wang while (i--) 8961d98b618SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, 8971d98b618SCaesar Wang thermal->sensors[i].tzd); 8981d98b618SCaesar Wang 899cbac8f63SCaesar Wang err_disable_pclk: 900cbac8f63SCaesar Wang clk_disable_unprepare(thermal->pclk); 901cbac8f63SCaesar Wang err_disable_clk: 902cbac8f63SCaesar Wang clk_disable_unprepare(thermal->clk); 903cbac8f63SCaesar Wang 904cbac8f63SCaesar Wang return error; 905cbac8f63SCaesar Wang } 906cbac8f63SCaesar Wang 907cbac8f63SCaesar Wang static int rockchip_thermal_remove(struct platform_device *pdev) 908cbac8f63SCaesar Wang { 909cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 910cbac8f63SCaesar Wang int i; 911cbac8f63SCaesar Wang 9121d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 913cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; 914cbac8f63SCaesar Wang 915cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(sensor, false); 916cbac8f63SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); 917cbac8f63SCaesar Wang } 918cbac8f63SCaesar Wang 919cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, false); 920cbac8f63SCaesar Wang 921cbac8f63SCaesar Wang clk_disable_unprepare(thermal->pclk); 922cbac8f63SCaesar Wang clk_disable_unprepare(thermal->clk); 923cbac8f63SCaesar Wang 924cbac8f63SCaesar Wang return 0; 925cbac8f63SCaesar Wang } 926cbac8f63SCaesar Wang 927cbac8f63SCaesar Wang static int __maybe_unused rockchip_thermal_suspend(struct device *dev) 928cbac8f63SCaesar Wang { 929cbac8f63SCaesar Wang struct platform_device *pdev = to_platform_device(dev); 930cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 931cbac8f63SCaesar Wang int i; 932cbac8f63SCaesar Wang 9331d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 934cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], false); 935cbac8f63SCaesar Wang 936cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, false); 937cbac8f63SCaesar Wang 938cbac8f63SCaesar Wang clk_disable(thermal->pclk); 939cbac8f63SCaesar Wang clk_disable(thermal->clk); 940cbac8f63SCaesar Wang 9417e38a5b1SCaesar Wang pinctrl_pm_select_sleep_state(dev); 9427e38a5b1SCaesar Wang 943cbac8f63SCaesar Wang return 0; 944cbac8f63SCaesar Wang } 945cbac8f63SCaesar Wang 946cbac8f63SCaesar Wang static int __maybe_unused rockchip_thermal_resume(struct device *dev) 947cbac8f63SCaesar Wang { 948cbac8f63SCaesar Wang struct platform_device *pdev = to_platform_device(dev); 949cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 950cbac8f63SCaesar Wang int i; 951cbac8f63SCaesar Wang int error; 952cbac8f63SCaesar Wang 953cbac8f63SCaesar Wang error = clk_enable(thermal->clk); 954cbac8f63SCaesar Wang if (error) 955cbac8f63SCaesar Wang return error; 956cbac8f63SCaesar Wang 957cbac8f63SCaesar Wang error = clk_enable(thermal->pclk); 958cbac8f63SCaesar Wang if (error) 959cbac8f63SCaesar Wang return error; 960cbac8f63SCaesar Wang 961cbac8f63SCaesar Wang rockchip_thermal_reset_controller(thermal->reset); 962cbac8f63SCaesar Wang 963cbac8f63SCaesar Wang thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 964cbac8f63SCaesar Wang 9651d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 9661d98b618SCaesar Wang int id = thermal->sensors[i].id; 967cbac8f63SCaesar Wang 968cbac8f63SCaesar Wang thermal->chip->set_tshut_mode(id, thermal->regs, 969cbac8f63SCaesar Wang thermal->tshut_mode); 970ce74110dSCaesar Wang thermal->chip->set_tshut_temp(thermal->chip->table, 971ce74110dSCaesar Wang id, thermal->regs, 972cbac8f63SCaesar Wang thermal->tshut_temp); 973cbac8f63SCaesar Wang } 974cbac8f63SCaesar Wang 975cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, true); 976cbac8f63SCaesar Wang 9771d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 978cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 979cbac8f63SCaesar Wang 9807e38a5b1SCaesar Wang pinctrl_pm_select_default_state(dev); 9817e38a5b1SCaesar Wang 982cbac8f63SCaesar Wang return 0; 983cbac8f63SCaesar Wang } 984cbac8f63SCaesar Wang 985cbac8f63SCaesar Wang static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops, 986cbac8f63SCaesar Wang rockchip_thermal_suspend, rockchip_thermal_resume); 987cbac8f63SCaesar Wang 988cbac8f63SCaesar Wang static struct platform_driver rockchip_thermal_driver = { 989cbac8f63SCaesar Wang .driver = { 990cbac8f63SCaesar Wang .name = "rockchip-thermal", 991cbac8f63SCaesar Wang .pm = &rockchip_thermal_pm_ops, 992cbac8f63SCaesar Wang .of_match_table = of_rockchip_thermal_match, 993cbac8f63SCaesar Wang }, 994cbac8f63SCaesar Wang .probe = rockchip_thermal_probe, 995cbac8f63SCaesar Wang .remove = rockchip_thermal_remove, 996cbac8f63SCaesar Wang }; 997cbac8f63SCaesar Wang 998cbac8f63SCaesar Wang module_platform_driver(rockchip_thermal_driver); 999cbac8f63SCaesar Wang 1000cbac8f63SCaesar Wang MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver"); 1001cbac8f63SCaesar Wang MODULE_AUTHOR("Rockchip, Inc."); 1002cbac8f63SCaesar Wang MODULE_LICENSE("GPL v2"); 1003cbac8f63SCaesar Wang MODULE_ALIAS("platform:rockchip-thermal"); 1004