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. 61952418a3SCaesar Wang * ADC_DECREMENT: the adc value is of diminishing.(e.g. rk3288_code_table) 62952418a3SCaesar Wang * ADC_INCREMENT: the adc value is incremental.(e.g. rk3368_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 138952418a3SCaesar Wang /** 139952418a3SCaesar Wang * TSADC Sensor Register description: 140952418a3SCaesar Wang * 141952418a3SCaesar Wang * TSADCV2_* are used for RK3288 SoCs, the other chips can reuse it. 142952418a3SCaesar Wang * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) 143952418a3SCaesar Wang * 144952418a3SCaesar Wang */ 145cbac8f63SCaesar Wang #define TSADCV2_AUTO_CON 0x04 146cbac8f63SCaesar Wang #define TSADCV2_INT_EN 0x08 147cbac8f63SCaesar Wang #define TSADCV2_INT_PD 0x0c 148cbac8f63SCaesar Wang #define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) 149cbac8f63SCaesar Wang #define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) 150cbac8f63SCaesar Wang #define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 151cbac8f63SCaesar Wang #define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 152cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD 0x68 153cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_HT 0x6c 154cbac8f63SCaesar Wang 155cbac8f63SCaesar Wang #define TSADCV2_AUTO_EN BIT(0) 156cbac8f63SCaesar Wang #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) 157cbac8f63SCaesar Wang #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) 1587ea38c6cSCaesar Wang /** 1597ea38c6cSCaesar Wang * TSADCV1_AUTO_Q_SEL_EN: 1607ea38c6cSCaesar Wang * whether select (1024 - tsadc_q) as output 1617ea38c6cSCaesar Wang * 1'b0:use tsadc_q as output(temperature-code is rising sequence) 1627ea38c6cSCaesar Wang * 1'b1:use(1024 - tsadc_q) as output (temperature-code is falling sequence) 1637ea38c6cSCaesar Wang */ 1647ea38c6cSCaesar Wang #define TSADCV3_AUTO_Q_SEL_EN BIT(1) 165cbac8f63SCaesar Wang 166cbac8f63SCaesar Wang #define TSADCV2_INT_SRC_EN(chn) BIT(chn) 167cbac8f63SCaesar Wang #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) 168cbac8f63SCaesar Wang #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) 169cbac8f63SCaesar Wang 170452e01b3SDmitry Torokhov #define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) 171952418a3SCaesar Wang #define TSADCV3_INT_PD_CLEAR_MASK ~BIT(16) 172cbac8f63SCaesar Wang 173cbac8f63SCaesar Wang #define TSADCV2_DATA_MASK 0xfff 17420f0af75SCaesar Wang #define TSADCV3_DATA_MASK 0x3ff 17520f0af75SCaesar Wang 176cbac8f63SCaesar Wang #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 177cbac8f63SCaesar Wang #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 178cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ 179cbac8f63SCaesar Wang #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ 180cbac8f63SCaesar Wang 181cbac8f63SCaesar Wang struct tsadc_table { 182d9a241cbSDmitry Torokhov u32 code; 183437df217SCaesar Wang int temp; 184cbac8f63SCaesar Wang }; 185cbac8f63SCaesar Wang 1867b02a5e7SCaesar Wang /** 1877b02a5e7SCaesar Wang * Note: 1887b02a5e7SCaesar Wang * Code to Temperature mapping of the Temperature sensor is a piece wise linear 1897b02a5e7SCaesar Wang * curve.Any temperature, code faling between to 2 give temperatures can be 1907b02a5e7SCaesar Wang * linearly interpolated. 1917b02a5e7SCaesar Wang * Code to Temperature mapping should be updated based on sillcon results. 1927b02a5e7SCaesar Wang */ 193952418a3SCaesar Wang static const struct tsadc_table rk3228_code_table[] = { 1947ea38c6cSCaesar Wang {0, -40000}, 1957ea38c6cSCaesar Wang {588, -40000}, 1967ea38c6cSCaesar Wang {593, -35000}, 1977ea38c6cSCaesar Wang {598, -30000}, 1987ea38c6cSCaesar Wang {603, -25000}, 1997ea38c6cSCaesar Wang {608, -20000}, 2007ea38c6cSCaesar Wang {613, -15000}, 2017ea38c6cSCaesar Wang {618, -10000}, 2027ea38c6cSCaesar Wang {623, -5000}, 2037ea38c6cSCaesar Wang {629, 0}, 2047ea38c6cSCaesar Wang {634, 5000}, 2057ea38c6cSCaesar Wang {639, 10000}, 2067ea38c6cSCaesar Wang {644, 15000}, 2077ea38c6cSCaesar Wang {649, 20000}, 2087ea38c6cSCaesar Wang {654, 25000}, 2097ea38c6cSCaesar Wang {660, 30000}, 2107ea38c6cSCaesar Wang {665, 35000}, 2117ea38c6cSCaesar Wang {670, 40000}, 2127ea38c6cSCaesar Wang {675, 45000}, 2137ea38c6cSCaesar Wang {681, 50000}, 2147ea38c6cSCaesar Wang {686, 55000}, 2157ea38c6cSCaesar Wang {691, 60000}, 2167ea38c6cSCaesar Wang {696, 65000}, 2177ea38c6cSCaesar Wang {702, 70000}, 2187ea38c6cSCaesar Wang {707, 75000}, 2197ea38c6cSCaesar Wang {712, 80000}, 2207ea38c6cSCaesar Wang {717, 85000}, 2217ea38c6cSCaesar Wang {723, 90000}, 2227ea38c6cSCaesar Wang {728, 95000}, 2237ea38c6cSCaesar Wang {733, 100000}, 2247ea38c6cSCaesar Wang {738, 105000}, 2257ea38c6cSCaesar Wang {744, 110000}, 2267ea38c6cSCaesar Wang {749, 115000}, 2277ea38c6cSCaesar Wang {754, 120000}, 2287ea38c6cSCaesar Wang {760, 125000}, 2297ea38c6cSCaesar Wang {TSADCV2_DATA_MASK, 125000}, 2307b02a5e7SCaesar Wang }; 2317b02a5e7SCaesar Wang 232952418a3SCaesar Wang static const struct tsadc_table rk3288_code_table[] = { 233cbac8f63SCaesar Wang {TSADCV2_DATA_MASK, -40000}, 234cbac8f63SCaesar Wang {3800, -40000}, 235cbac8f63SCaesar Wang {3792, -35000}, 236cbac8f63SCaesar Wang {3783, -30000}, 237cbac8f63SCaesar Wang {3774, -25000}, 238cbac8f63SCaesar Wang {3765, -20000}, 239cbac8f63SCaesar Wang {3756, -15000}, 240cbac8f63SCaesar Wang {3747, -10000}, 241cbac8f63SCaesar Wang {3737, -5000}, 242cbac8f63SCaesar Wang {3728, 0}, 243cbac8f63SCaesar Wang {3718, 5000}, 244cbac8f63SCaesar Wang {3708, 10000}, 245cbac8f63SCaesar Wang {3698, 15000}, 246cbac8f63SCaesar Wang {3688, 20000}, 247cbac8f63SCaesar Wang {3678, 25000}, 248cbac8f63SCaesar Wang {3667, 30000}, 249cbac8f63SCaesar Wang {3656, 35000}, 250cbac8f63SCaesar Wang {3645, 40000}, 251cbac8f63SCaesar Wang {3634, 45000}, 252cbac8f63SCaesar Wang {3623, 50000}, 253cbac8f63SCaesar Wang {3611, 55000}, 254cbac8f63SCaesar Wang {3600, 60000}, 255cbac8f63SCaesar Wang {3588, 65000}, 256cbac8f63SCaesar Wang {3575, 70000}, 257cbac8f63SCaesar Wang {3563, 75000}, 258cbac8f63SCaesar Wang {3550, 80000}, 259cbac8f63SCaesar Wang {3537, 85000}, 260cbac8f63SCaesar Wang {3524, 90000}, 261cbac8f63SCaesar Wang {3510, 95000}, 262cbac8f63SCaesar Wang {3496, 100000}, 263cbac8f63SCaesar Wang {3482, 105000}, 264cbac8f63SCaesar Wang {3467, 110000}, 265cbac8f63SCaesar Wang {3452, 115000}, 266cbac8f63SCaesar Wang {3437, 120000}, 267cbac8f63SCaesar Wang {3421, 125000}, 268cbac8f63SCaesar Wang }; 269cbac8f63SCaesar Wang 270952418a3SCaesar Wang static const struct tsadc_table rk3368_code_table[] = { 27120f0af75SCaesar Wang {0, -40000}, 27220f0af75SCaesar Wang {106, -40000}, 27320f0af75SCaesar Wang {108, -35000}, 27420f0af75SCaesar Wang {110, -30000}, 27520f0af75SCaesar Wang {112, -25000}, 27620f0af75SCaesar Wang {114, -20000}, 27720f0af75SCaesar Wang {116, -15000}, 27820f0af75SCaesar Wang {118, -10000}, 27920f0af75SCaesar Wang {120, -5000}, 28020f0af75SCaesar Wang {122, 0}, 28120f0af75SCaesar Wang {124, 5000}, 28220f0af75SCaesar Wang {126, 10000}, 28320f0af75SCaesar Wang {128, 15000}, 28420f0af75SCaesar Wang {130, 20000}, 28520f0af75SCaesar Wang {132, 25000}, 28620f0af75SCaesar Wang {134, 30000}, 28720f0af75SCaesar Wang {136, 35000}, 28820f0af75SCaesar Wang {138, 40000}, 28920f0af75SCaesar Wang {140, 45000}, 29020f0af75SCaesar Wang {142, 50000}, 29120f0af75SCaesar Wang {144, 55000}, 29220f0af75SCaesar Wang {146, 60000}, 29320f0af75SCaesar Wang {148, 65000}, 29420f0af75SCaesar Wang {150, 70000}, 29520f0af75SCaesar Wang {152, 75000}, 29620f0af75SCaesar Wang {154, 80000}, 29720f0af75SCaesar Wang {156, 85000}, 29820f0af75SCaesar Wang {158, 90000}, 29920f0af75SCaesar Wang {160, 95000}, 30020f0af75SCaesar Wang {162, 100000}, 30120f0af75SCaesar Wang {163, 105000}, 30220f0af75SCaesar Wang {165, 110000}, 30320f0af75SCaesar Wang {167, 115000}, 30420f0af75SCaesar Wang {169, 120000}, 30520f0af75SCaesar Wang {171, 125000}, 30620f0af75SCaesar Wang {TSADCV3_DATA_MASK, 125000}, 30720f0af75SCaesar Wang }; 30820f0af75SCaesar Wang 309952418a3SCaesar Wang static const struct tsadc_table rk3399_code_table[] = { 3107ea38c6cSCaesar Wang {0, -40000}, 3117ea38c6cSCaesar Wang {593, -40000}, 3127ea38c6cSCaesar Wang {598, -35000}, 3137ea38c6cSCaesar Wang {603, -30000}, 3147ea38c6cSCaesar Wang {609, -25000}, 3157ea38c6cSCaesar Wang {614, -20000}, 3167ea38c6cSCaesar Wang {619, -15000}, 3177ea38c6cSCaesar Wang {625, -10000}, 3187ea38c6cSCaesar Wang {630, -5000}, 3197ea38c6cSCaesar Wang {635, 0}, 3207ea38c6cSCaesar Wang {641, 5000}, 3217ea38c6cSCaesar Wang {646, 10000}, 3227ea38c6cSCaesar Wang {651, 15000}, 3237ea38c6cSCaesar Wang {657, 20000}, 3247ea38c6cSCaesar Wang {662, 25000}, 3257ea38c6cSCaesar Wang {667, 30000}, 3267ea38c6cSCaesar Wang {673, 35000}, 3277ea38c6cSCaesar Wang {678, 40000}, 3287ea38c6cSCaesar Wang {684, 45000}, 3297ea38c6cSCaesar Wang {689, 50000}, 3307ea38c6cSCaesar Wang {694, 55000}, 3317ea38c6cSCaesar Wang {700, 60000}, 3327ea38c6cSCaesar Wang {705, 65000}, 3337ea38c6cSCaesar Wang {711, 70000}, 3347ea38c6cSCaesar Wang {716, 75000}, 3357ea38c6cSCaesar Wang {722, 80000}, 3367ea38c6cSCaesar Wang {727, 85000}, 3377ea38c6cSCaesar Wang {733, 90000}, 3387ea38c6cSCaesar Wang {738, 95000}, 3397ea38c6cSCaesar Wang {743, 100000}, 3407ea38c6cSCaesar Wang {749, 105000}, 3417ea38c6cSCaesar Wang {754, 110000}, 3427ea38c6cSCaesar Wang {760, 115000}, 3437ea38c6cSCaesar Wang {765, 120000}, 3447ea38c6cSCaesar Wang {771, 125000}, 3457ea38c6cSCaesar Wang {TSADCV3_DATA_MASK, 125000}, 346b0d70338SCaesar Wang }; 347b0d70338SCaesar Wang 348ce74110dSCaesar Wang static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, 349437df217SCaesar Wang int temp) 350cbac8f63SCaesar Wang { 351cbac8f63SCaesar Wang int high, low, mid; 352cbac8f63SCaesar Wang 353cbac8f63SCaesar Wang low = 0; 354ce74110dSCaesar Wang high = table.length - 1; 355cbac8f63SCaesar Wang mid = (high + low) / 2; 356cbac8f63SCaesar Wang 357ce74110dSCaesar Wang if (temp < table.id[low].temp || temp > table.id[high].temp) 358cbac8f63SCaesar Wang return 0; 359cbac8f63SCaesar Wang 360cbac8f63SCaesar Wang while (low <= high) { 361ce74110dSCaesar Wang if (temp == table.id[mid].temp) 362ce74110dSCaesar Wang return table.id[mid].code; 363ce74110dSCaesar Wang else if (temp < table.id[mid].temp) 364cbac8f63SCaesar Wang high = mid - 1; 365cbac8f63SCaesar Wang else 366cbac8f63SCaesar Wang low = mid + 1; 367cbac8f63SCaesar Wang mid = (low + high) / 2; 368cbac8f63SCaesar Wang } 369cbac8f63SCaesar Wang 370cbac8f63SCaesar Wang return 0; 371cbac8f63SCaesar Wang } 372cbac8f63SCaesar Wang 373ce74110dSCaesar Wang static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, 374ce74110dSCaesar Wang int *temp) 375cbac8f63SCaesar Wang { 376d9a241cbSDmitry Torokhov unsigned int low = 1; 377ce74110dSCaesar Wang unsigned int high = table.length - 1; 3781e9a1aeaSCaesar Wang unsigned int mid = (low + high) / 2; 3791e9a1aeaSCaesar Wang unsigned int num; 3801e9a1aeaSCaesar Wang unsigned long denom; 381cbac8f63SCaesar Wang 382ce74110dSCaesar Wang WARN_ON(table.length < 2); 383cbac8f63SCaesar Wang 384020ba95dSCaesar Wang switch (table.mode) { 385020ba95dSCaesar Wang case ADC_DECREMENT: 386ce74110dSCaesar Wang code &= table.data_mask; 387ce74110dSCaesar Wang if (code < table.id[high].code) 388d9a241cbSDmitry Torokhov return -EAGAIN; /* Incorrect reading */ 389d9a241cbSDmitry Torokhov 390d9a241cbSDmitry Torokhov while (low <= high) { 391ce74110dSCaesar Wang if (code >= table.id[mid].code && 392ce74110dSCaesar Wang code < table.id[mid - 1].code) 3931e9a1aeaSCaesar Wang break; 394ce74110dSCaesar Wang else if (code < table.id[mid].code) 395cbac8f63SCaesar Wang low = mid + 1; 396cbac8f63SCaesar Wang else 397cbac8f63SCaesar Wang high = mid - 1; 398020ba95dSCaesar Wang 399cbac8f63SCaesar Wang mid = (low + high) / 2; 400cbac8f63SCaesar Wang } 401020ba95dSCaesar Wang break; 402020ba95dSCaesar Wang case ADC_INCREMENT: 403020ba95dSCaesar Wang code &= table.data_mask; 404020ba95dSCaesar Wang if (code < table.id[low].code) 405020ba95dSCaesar Wang return -EAGAIN; /* Incorrect reading */ 406020ba95dSCaesar Wang 407020ba95dSCaesar Wang while (low <= high) { 408020ba95dSCaesar Wang if (code >= table.id[mid - 1].code && 409020ba95dSCaesar Wang code < table.id[mid].code) 410020ba95dSCaesar Wang break; 411020ba95dSCaesar Wang else if (code > table.id[mid].code) 412020ba95dSCaesar Wang low = mid + 1; 413020ba95dSCaesar Wang else 414020ba95dSCaesar Wang high = mid - 1; 415020ba95dSCaesar Wang 416020ba95dSCaesar Wang mid = (low + high) / 2; 417020ba95dSCaesar Wang } 418020ba95dSCaesar Wang break; 419020ba95dSCaesar Wang default: 420020ba95dSCaesar Wang pr_err("Invalid the conversion table\n"); 421020ba95dSCaesar Wang } 422cbac8f63SCaesar Wang 4231e9a1aeaSCaesar Wang /* 4241e9a1aeaSCaesar Wang * The 5C granularity provided by the table is too much. Let's 4251e9a1aeaSCaesar Wang * assume that the relationship between sensor readings and 4261e9a1aeaSCaesar Wang * temperature between 2 table entries is linear and interpolate 4271e9a1aeaSCaesar Wang * to produce less granular result. 4281e9a1aeaSCaesar Wang */ 4291d37a037SElaine Zhang num = table.id[mid].temp - table.id[mid - 1].temp; 430020ba95dSCaesar Wang num *= abs(table.id[mid - 1].code - code); 431020ba95dSCaesar Wang denom = abs(table.id[mid - 1].code - table.id[mid].code); 432ce74110dSCaesar Wang *temp = table.id[mid - 1].temp + (num / denom); 433d9a241cbSDmitry Torokhov 434d9a241cbSDmitry Torokhov return 0; 435cbac8f63SCaesar Wang } 436cbac8f63SCaesar Wang 437cbac8f63SCaesar Wang /** 438144c5565SCaesar Wang * rk_tsadcv2_initialize - initialize TASDC Controller. 439144c5565SCaesar Wang * 440144c5565SCaesar Wang * (1) Set TSADC_V2_AUTO_PERIOD: 441144c5565SCaesar Wang * Configure the interleave between every two accessing of 442144c5565SCaesar Wang * TSADC in normal operation. 443144c5565SCaesar Wang * 444144c5565SCaesar Wang * (2) Set TSADCV2_AUTO_PERIOD_HT: 445144c5565SCaesar Wang * Configure the interleave between every two accessing of 446144c5565SCaesar Wang * TSADC after the temperature is higher than COM_SHUT or COM_INT. 447144c5565SCaesar Wang * 448144c5565SCaesar Wang * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE: 449144c5565SCaesar Wang * If the temperature is higher than COMP_INT or COMP_SHUT for 450cbac8f63SCaesar Wang * "debounce" times, TSADC controller will generate interrupt or TSHUT. 451cbac8f63SCaesar Wang */ 452cbac8f63SCaesar Wang static void rk_tsadcv2_initialize(void __iomem *regs, 453cbac8f63SCaesar Wang enum tshut_polarity tshut_polarity) 454cbac8f63SCaesar Wang { 455cbac8f63SCaesar Wang if (tshut_polarity == TSHUT_HIGH_ACTIVE) 456452e01b3SDmitry Torokhov writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, 457cbac8f63SCaesar Wang regs + TSADCV2_AUTO_CON); 458cbac8f63SCaesar Wang else 459452e01b3SDmitry Torokhov writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, 460cbac8f63SCaesar Wang regs + TSADCV2_AUTO_CON); 461cbac8f63SCaesar Wang 462cbac8f63SCaesar Wang writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); 463cbac8f63SCaesar Wang writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, 464cbac8f63SCaesar Wang regs + TSADCV2_HIGHT_INT_DEBOUNCE); 465cbac8f63SCaesar Wang writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, 466cbac8f63SCaesar Wang regs + TSADCV2_AUTO_PERIOD_HT); 467cbac8f63SCaesar Wang writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, 468cbac8f63SCaesar Wang regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); 469cbac8f63SCaesar Wang } 470cbac8f63SCaesar Wang 471cbac8f63SCaesar Wang static void rk_tsadcv2_irq_ack(void __iomem *regs) 472cbac8f63SCaesar Wang { 473cbac8f63SCaesar Wang u32 val; 474cbac8f63SCaesar Wang 475cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_PD); 476452e01b3SDmitry Torokhov writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); 477cbac8f63SCaesar Wang } 478cbac8f63SCaesar Wang 479952418a3SCaesar Wang static void rk_tsadcv3_irq_ack(void __iomem *regs) 480952418a3SCaesar Wang { 481952418a3SCaesar Wang u32 val; 482952418a3SCaesar Wang 483952418a3SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_PD); 484952418a3SCaesar Wang writel_relaxed(val & TSADCV3_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); 485952418a3SCaesar Wang } 486952418a3SCaesar Wang 487cbac8f63SCaesar Wang static void rk_tsadcv2_control(void __iomem *regs, bool enable) 488cbac8f63SCaesar Wang { 489cbac8f63SCaesar Wang u32 val; 490cbac8f63SCaesar Wang 491cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_AUTO_CON); 492cbac8f63SCaesar Wang if (enable) 493cbac8f63SCaesar Wang val |= TSADCV2_AUTO_EN; 494cbac8f63SCaesar Wang else 495cbac8f63SCaesar Wang val &= ~TSADCV2_AUTO_EN; 496cbac8f63SCaesar Wang 497cbac8f63SCaesar Wang writel_relaxed(val, regs + TSADCV2_AUTO_CON); 498cbac8f63SCaesar Wang } 499cbac8f63SCaesar Wang 5007ea38c6cSCaesar Wang /** 5017ea38c6cSCaesar Wang * @rk_tsadcv3_control: 5027ea38c6cSCaesar Wang * TSADC controller works at auto mode, and some SoCs need set the tsadc_q_sel 5037ea38c6cSCaesar Wang * bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output adc value if 5047ea38c6cSCaesar Wang * setting this bit to enable. 5057ea38c6cSCaesar Wang */ 5067ea38c6cSCaesar Wang static void rk_tsadcv3_control(void __iomem *regs, bool enable) 5077ea38c6cSCaesar Wang { 5087ea38c6cSCaesar Wang u32 val; 5097ea38c6cSCaesar Wang 5107ea38c6cSCaesar Wang val = readl_relaxed(regs + TSADCV2_AUTO_CON); 5117ea38c6cSCaesar Wang if (enable) 5127ea38c6cSCaesar Wang val |= TSADCV2_AUTO_EN | TSADCV3_AUTO_Q_SEL_EN; 5137ea38c6cSCaesar Wang else 5147ea38c6cSCaesar Wang val &= ~TSADCV2_AUTO_EN; 5157ea38c6cSCaesar Wang 5167ea38c6cSCaesar Wang writel_relaxed(val, regs + TSADCV2_AUTO_CON); 5177ea38c6cSCaesar Wang } 5187ea38c6cSCaesar Wang 519ce74110dSCaesar Wang static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, 520ce74110dSCaesar Wang int chn, void __iomem *regs, int *temp) 521cbac8f63SCaesar Wang { 522cbac8f63SCaesar Wang u32 val; 523cbac8f63SCaesar Wang 524cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_DATA(chn)); 525cbac8f63SCaesar Wang 526ce74110dSCaesar Wang return rk_tsadcv2_code_to_temp(table, val, temp); 527cbac8f63SCaesar Wang } 528cbac8f63SCaesar Wang 529ce74110dSCaesar Wang static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, 530437df217SCaesar Wang int chn, void __iomem *regs, int temp) 531cbac8f63SCaesar Wang { 532cbac8f63SCaesar Wang u32 tshut_value, val; 533cbac8f63SCaesar Wang 534ce74110dSCaesar Wang tshut_value = rk_tsadcv2_temp_to_code(table, temp); 535cbac8f63SCaesar Wang writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); 536cbac8f63SCaesar Wang 537cbac8f63SCaesar Wang /* TSHUT will be valid */ 538cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_AUTO_CON); 539cbac8f63SCaesar Wang writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON); 540cbac8f63SCaesar Wang } 541cbac8f63SCaesar Wang 542cbac8f63SCaesar Wang static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, 543cbac8f63SCaesar Wang enum tshut_mode mode) 544cbac8f63SCaesar Wang { 545cbac8f63SCaesar Wang u32 val; 546cbac8f63SCaesar Wang 547cbac8f63SCaesar Wang val = readl_relaxed(regs + TSADCV2_INT_EN); 548cbac8f63SCaesar Wang if (mode == TSHUT_MODE_GPIO) { 549cbac8f63SCaesar Wang val &= ~TSADCV2_SHUT_2CRU_SRC_EN(chn); 550cbac8f63SCaesar Wang val |= TSADCV2_SHUT_2GPIO_SRC_EN(chn); 551cbac8f63SCaesar Wang } else { 552cbac8f63SCaesar Wang val &= ~TSADCV2_SHUT_2GPIO_SRC_EN(chn); 553cbac8f63SCaesar Wang val |= TSADCV2_SHUT_2CRU_SRC_EN(chn); 554cbac8f63SCaesar Wang } 555cbac8f63SCaesar Wang 556cbac8f63SCaesar Wang writel_relaxed(val, regs + TSADCV2_INT_EN); 557cbac8f63SCaesar Wang } 558cbac8f63SCaesar Wang 5597b02a5e7SCaesar Wang static const struct rockchip_tsadc_chip rk3228_tsadc_data = { 5607b02a5e7SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 5617b02a5e7SCaesar Wang .chn_num = 1, /* one channel for tsadc */ 5627b02a5e7SCaesar Wang 5637b02a5e7SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 5647b02a5e7SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 5657b02a5e7SCaesar Wang .tshut_temp = 95000, 5667b02a5e7SCaesar Wang 5677b02a5e7SCaesar Wang .initialize = rk_tsadcv2_initialize, 568952418a3SCaesar Wang .irq_ack = rk_tsadcv3_irq_ack, 5697ea38c6cSCaesar Wang .control = rk_tsadcv3_control, 5707b02a5e7SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 5717b02a5e7SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 5727b02a5e7SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 5737b02a5e7SCaesar Wang 5747b02a5e7SCaesar Wang .table = { 575952418a3SCaesar Wang .id = rk3228_code_table, 576952418a3SCaesar Wang .length = ARRAY_SIZE(rk3228_code_table), 5777b02a5e7SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 5787ea38c6cSCaesar Wang .mode = ADC_INCREMENT, 5797b02a5e7SCaesar Wang }, 5807b02a5e7SCaesar Wang }; 5817b02a5e7SCaesar Wang 582cbac8f63SCaesar Wang static const struct rockchip_tsadc_chip rk3288_tsadc_data = { 5831d98b618SCaesar Wang .chn_id[SENSOR_CPU] = 1, /* cpu sensor is channel 1 */ 5841d98b618SCaesar Wang .chn_id[SENSOR_GPU] = 2, /* gpu sensor is channel 2 */ 5851d98b618SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 5861d98b618SCaesar Wang 587cbac8f63SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 588cbac8f63SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 589cbac8f63SCaesar Wang .tshut_temp = 95000, 590cbac8f63SCaesar Wang 591cbac8f63SCaesar Wang .initialize = rk_tsadcv2_initialize, 592cbac8f63SCaesar Wang .irq_ack = rk_tsadcv2_irq_ack, 593cbac8f63SCaesar Wang .control = rk_tsadcv2_control, 594cbac8f63SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 595cbac8f63SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 596cbac8f63SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 597ce74110dSCaesar Wang 598ce74110dSCaesar Wang .table = { 599952418a3SCaesar Wang .id = rk3288_code_table, 600952418a3SCaesar Wang .length = ARRAY_SIZE(rk3288_code_table), 601ce74110dSCaesar Wang .data_mask = TSADCV2_DATA_MASK, 602020ba95dSCaesar Wang .mode = ADC_DECREMENT, 603ce74110dSCaesar Wang }, 604cbac8f63SCaesar Wang }; 605cbac8f63SCaesar Wang 60620f0af75SCaesar Wang static const struct rockchip_tsadc_chip rk3368_tsadc_data = { 60720f0af75SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 60820f0af75SCaesar Wang .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ 60920f0af75SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 61020f0af75SCaesar Wang 61120f0af75SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 61220f0af75SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 61320f0af75SCaesar Wang .tshut_temp = 95000, 61420f0af75SCaesar Wang 61520f0af75SCaesar Wang .initialize = rk_tsadcv2_initialize, 61620f0af75SCaesar Wang .irq_ack = rk_tsadcv2_irq_ack, 61720f0af75SCaesar Wang .control = rk_tsadcv2_control, 61820f0af75SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 61920f0af75SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 62020f0af75SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 62120f0af75SCaesar Wang 62220f0af75SCaesar Wang .table = { 623952418a3SCaesar Wang .id = rk3368_code_table, 624952418a3SCaesar Wang .length = ARRAY_SIZE(rk3368_code_table), 62520f0af75SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 62620f0af75SCaesar Wang .mode = ADC_INCREMENT, 62720f0af75SCaesar Wang }, 62820f0af75SCaesar Wang }; 62920f0af75SCaesar Wang 630b0d70338SCaesar Wang static const struct rockchip_tsadc_chip rk3399_tsadc_data = { 631b0d70338SCaesar Wang .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ 632b0d70338SCaesar Wang .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ 633b0d70338SCaesar Wang .chn_num = 2, /* two channels for tsadc */ 634b0d70338SCaesar Wang 635b0d70338SCaesar Wang .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 636b0d70338SCaesar Wang .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 637b0d70338SCaesar Wang .tshut_temp = 95000, 638b0d70338SCaesar Wang 639b0d70338SCaesar Wang .initialize = rk_tsadcv2_initialize, 640952418a3SCaesar Wang .irq_ack = rk_tsadcv3_irq_ack, 6417ea38c6cSCaesar Wang .control = rk_tsadcv3_control, 642b0d70338SCaesar Wang .get_temp = rk_tsadcv2_get_temp, 643b0d70338SCaesar Wang .set_tshut_temp = rk_tsadcv2_tshut_temp, 644b0d70338SCaesar Wang .set_tshut_mode = rk_tsadcv2_tshut_mode, 645b0d70338SCaesar Wang 646b0d70338SCaesar Wang .table = { 647952418a3SCaesar Wang .id = rk3399_code_table, 648952418a3SCaesar Wang .length = ARRAY_SIZE(rk3399_code_table), 649b0d70338SCaesar Wang .data_mask = TSADCV3_DATA_MASK, 6507ea38c6cSCaesar Wang .mode = ADC_INCREMENT, 651b0d70338SCaesar Wang }, 652b0d70338SCaesar Wang }; 653b0d70338SCaesar Wang 654cbac8f63SCaesar Wang static const struct of_device_id of_rockchip_thermal_match[] = { 655cbac8f63SCaesar Wang { 6567b02a5e7SCaesar Wang .compatible = "rockchip,rk3228-tsadc", 6577b02a5e7SCaesar Wang .data = (void *)&rk3228_tsadc_data, 6587b02a5e7SCaesar Wang }, 6597b02a5e7SCaesar Wang { 660cbac8f63SCaesar Wang .compatible = "rockchip,rk3288-tsadc", 661cbac8f63SCaesar Wang .data = (void *)&rk3288_tsadc_data, 662cbac8f63SCaesar Wang }, 66320f0af75SCaesar Wang { 66420f0af75SCaesar Wang .compatible = "rockchip,rk3368-tsadc", 66520f0af75SCaesar Wang .data = (void *)&rk3368_tsadc_data, 66620f0af75SCaesar Wang }, 667b0d70338SCaesar Wang { 668b0d70338SCaesar Wang .compatible = "rockchip,rk3399-tsadc", 669b0d70338SCaesar Wang .data = (void *)&rk3399_tsadc_data, 670b0d70338SCaesar Wang }, 671cbac8f63SCaesar Wang { /* end */ }, 672cbac8f63SCaesar Wang }; 673cbac8f63SCaesar Wang MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); 674cbac8f63SCaesar Wang 675cbac8f63SCaesar Wang static void 676cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on) 677cbac8f63SCaesar Wang { 678cbac8f63SCaesar Wang struct thermal_zone_device *tzd = sensor->tzd; 679cbac8f63SCaesar Wang 680cbac8f63SCaesar Wang tzd->ops->set_mode(tzd, 681cbac8f63SCaesar Wang on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); 682cbac8f63SCaesar Wang } 683cbac8f63SCaesar Wang 684cbac8f63SCaesar Wang static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) 685cbac8f63SCaesar Wang { 686cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = dev; 687cbac8f63SCaesar Wang int i; 688cbac8f63SCaesar Wang 689cbac8f63SCaesar Wang dev_dbg(&thermal->pdev->dev, "thermal alarm\n"); 690cbac8f63SCaesar Wang 691cbac8f63SCaesar Wang thermal->chip->irq_ack(thermal->regs); 692cbac8f63SCaesar Wang 6931d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 694cbac8f63SCaesar Wang thermal_zone_device_update(thermal->sensors[i].tzd); 695cbac8f63SCaesar Wang 696cbac8f63SCaesar Wang return IRQ_HANDLED; 697cbac8f63SCaesar Wang } 698cbac8f63SCaesar Wang 69917e8351aSSascha Hauer static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) 700cbac8f63SCaesar Wang { 701cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor = _sensor; 702cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = sensor->thermal; 703cbac8f63SCaesar Wang const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip; 704cbac8f63SCaesar Wang int retval; 705cbac8f63SCaesar Wang 706ce74110dSCaesar Wang retval = tsadc->get_temp(tsadc->table, 707ce74110dSCaesar Wang sensor->id, thermal->regs, out_temp); 70817e8351aSSascha Hauer dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n", 709cbac8f63SCaesar Wang sensor->id, *out_temp, retval); 710cbac8f63SCaesar Wang 711cbac8f63SCaesar Wang return retval; 712cbac8f63SCaesar Wang } 713cbac8f63SCaesar Wang 714cbac8f63SCaesar Wang static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = { 715cbac8f63SCaesar Wang .get_temp = rockchip_thermal_get_temp, 716cbac8f63SCaesar Wang }; 717cbac8f63SCaesar Wang 718cbac8f63SCaesar Wang static int rockchip_configure_from_dt(struct device *dev, 719cbac8f63SCaesar Wang struct device_node *np, 720cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal) 721cbac8f63SCaesar Wang { 722cbac8f63SCaesar Wang u32 shut_temp, tshut_mode, tshut_polarity; 723cbac8f63SCaesar Wang 724cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) { 725cbac8f63SCaesar Wang dev_warn(dev, 726437df217SCaesar Wang "Missing tshut temp property, using default %d\n", 727cbac8f63SCaesar Wang thermal->chip->tshut_temp); 728cbac8f63SCaesar Wang thermal->tshut_temp = thermal->chip->tshut_temp; 729cbac8f63SCaesar Wang } else { 73043b4eb9fSCaesar Wang if (shut_temp > INT_MAX) { 731437df217SCaesar Wang dev_err(dev, "Invalid tshut temperature specified: %d\n", 73243b4eb9fSCaesar Wang shut_temp); 733cbac8f63SCaesar Wang return -ERANGE; 734cbac8f63SCaesar Wang } 73543b4eb9fSCaesar Wang thermal->tshut_temp = shut_temp; 73643b4eb9fSCaesar Wang } 737cbac8f63SCaesar Wang 738cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) { 739cbac8f63SCaesar Wang dev_warn(dev, 740cbac8f63SCaesar Wang "Missing tshut mode property, using default (%s)\n", 741cbac8f63SCaesar Wang thermal->chip->tshut_mode == TSHUT_MODE_GPIO ? 742cbac8f63SCaesar Wang "gpio" : "cru"); 743cbac8f63SCaesar Wang thermal->tshut_mode = thermal->chip->tshut_mode; 744cbac8f63SCaesar Wang } else { 745cbac8f63SCaesar Wang thermal->tshut_mode = tshut_mode; 746cbac8f63SCaesar Wang } 747cbac8f63SCaesar Wang 748cbac8f63SCaesar Wang if (thermal->tshut_mode > 1) { 749cbac8f63SCaesar Wang dev_err(dev, "Invalid tshut mode specified: %d\n", 750cbac8f63SCaesar Wang thermal->tshut_mode); 751cbac8f63SCaesar Wang return -EINVAL; 752cbac8f63SCaesar Wang } 753cbac8f63SCaesar Wang 754cbac8f63SCaesar Wang if (of_property_read_u32(np, "rockchip,hw-tshut-polarity", 755cbac8f63SCaesar Wang &tshut_polarity)) { 756cbac8f63SCaesar Wang dev_warn(dev, 757cbac8f63SCaesar Wang "Missing tshut-polarity property, using default (%s)\n", 758cbac8f63SCaesar Wang thermal->chip->tshut_polarity == TSHUT_LOW_ACTIVE ? 759cbac8f63SCaesar Wang "low" : "high"); 760cbac8f63SCaesar Wang thermal->tshut_polarity = thermal->chip->tshut_polarity; 761cbac8f63SCaesar Wang } else { 762cbac8f63SCaesar Wang thermal->tshut_polarity = tshut_polarity; 763cbac8f63SCaesar Wang } 764cbac8f63SCaesar Wang 765cbac8f63SCaesar Wang if (thermal->tshut_polarity > 1) { 766cbac8f63SCaesar Wang dev_err(dev, "Invalid tshut-polarity specified: %d\n", 767cbac8f63SCaesar Wang thermal->tshut_polarity); 768cbac8f63SCaesar Wang return -EINVAL; 769cbac8f63SCaesar Wang } 770cbac8f63SCaesar Wang 771cbac8f63SCaesar Wang return 0; 772cbac8f63SCaesar Wang } 773cbac8f63SCaesar Wang 774cbac8f63SCaesar Wang static int 775cbac8f63SCaesar Wang rockchip_thermal_register_sensor(struct platform_device *pdev, 776cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal, 777cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor, 7781d98b618SCaesar Wang int id) 779cbac8f63SCaesar Wang { 780cbac8f63SCaesar Wang const struct rockchip_tsadc_chip *tsadc = thermal->chip; 781cbac8f63SCaesar Wang int error; 782cbac8f63SCaesar Wang 783cbac8f63SCaesar Wang tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); 784ce74110dSCaesar Wang tsadc->set_tshut_temp(tsadc->table, id, thermal->regs, 785ce74110dSCaesar Wang thermal->tshut_temp); 786cbac8f63SCaesar Wang 787cbac8f63SCaesar Wang sensor->thermal = thermal; 788cbac8f63SCaesar Wang sensor->id = id; 789cbac8f63SCaesar Wang sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor, 790cbac8f63SCaesar Wang &rockchip_of_thermal_ops); 791cbac8f63SCaesar Wang if (IS_ERR(sensor->tzd)) { 792cbac8f63SCaesar Wang error = PTR_ERR(sensor->tzd); 793cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to register sensor %d: %d\n", 794cbac8f63SCaesar Wang id, error); 795cbac8f63SCaesar Wang return error; 796cbac8f63SCaesar Wang } 797cbac8f63SCaesar Wang 798cbac8f63SCaesar Wang return 0; 799cbac8f63SCaesar Wang } 800cbac8f63SCaesar Wang 80113c1cfdaSCaesar Wang /** 802cbac8f63SCaesar Wang * Reset TSADC Controller, reset all tsadc registers. 803cbac8f63SCaesar Wang */ 804cbac8f63SCaesar Wang static void rockchip_thermal_reset_controller(struct reset_control *reset) 805cbac8f63SCaesar Wang { 806cbac8f63SCaesar Wang reset_control_assert(reset); 807cbac8f63SCaesar Wang usleep_range(10, 20); 808cbac8f63SCaesar Wang reset_control_deassert(reset); 809cbac8f63SCaesar Wang } 810cbac8f63SCaesar Wang 811cbac8f63SCaesar Wang static int rockchip_thermal_probe(struct platform_device *pdev) 812cbac8f63SCaesar Wang { 813cbac8f63SCaesar Wang struct device_node *np = pdev->dev.of_node; 814cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal; 815cbac8f63SCaesar Wang const struct of_device_id *match; 816cbac8f63SCaesar Wang struct resource *res; 817cbac8f63SCaesar Wang int irq; 8181d98b618SCaesar Wang int i, j; 819cbac8f63SCaesar Wang int error; 820cbac8f63SCaesar Wang 821cbac8f63SCaesar Wang match = of_match_node(of_rockchip_thermal_match, np); 822cbac8f63SCaesar Wang if (!match) 823cbac8f63SCaesar Wang return -ENXIO; 824cbac8f63SCaesar Wang 825cbac8f63SCaesar Wang irq = platform_get_irq(pdev, 0); 826cbac8f63SCaesar Wang if (irq < 0) { 827cbac8f63SCaesar Wang dev_err(&pdev->dev, "no irq resource?\n"); 828cbac8f63SCaesar Wang return -EINVAL; 829cbac8f63SCaesar Wang } 830cbac8f63SCaesar Wang 831cbac8f63SCaesar Wang thermal = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data), 832cbac8f63SCaesar Wang GFP_KERNEL); 833cbac8f63SCaesar Wang if (!thermal) 834cbac8f63SCaesar Wang return -ENOMEM; 835cbac8f63SCaesar Wang 836cbac8f63SCaesar Wang thermal->pdev = pdev; 837cbac8f63SCaesar Wang 838cbac8f63SCaesar Wang thermal->chip = (const struct rockchip_tsadc_chip *)match->data; 839cbac8f63SCaesar Wang if (!thermal->chip) 840cbac8f63SCaesar Wang return -EINVAL; 841cbac8f63SCaesar Wang 842cbac8f63SCaesar Wang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 843cbac8f63SCaesar Wang thermal->regs = devm_ioremap_resource(&pdev->dev, res); 844cbac8f63SCaesar Wang if (IS_ERR(thermal->regs)) 845cbac8f63SCaesar Wang return PTR_ERR(thermal->regs); 846cbac8f63SCaesar Wang 847cbac8f63SCaesar Wang thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb"); 848cbac8f63SCaesar Wang if (IS_ERR(thermal->reset)) { 849cbac8f63SCaesar Wang error = PTR_ERR(thermal->reset); 850cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error); 851cbac8f63SCaesar Wang return error; 852cbac8f63SCaesar Wang } 853cbac8f63SCaesar Wang 854cbac8f63SCaesar Wang thermal->clk = devm_clk_get(&pdev->dev, "tsadc"); 855cbac8f63SCaesar Wang if (IS_ERR(thermal->clk)) { 856cbac8f63SCaesar Wang error = PTR_ERR(thermal->clk); 857cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get tsadc clock: %d\n", error); 858cbac8f63SCaesar Wang return error; 859cbac8f63SCaesar Wang } 860cbac8f63SCaesar Wang 861cbac8f63SCaesar Wang thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 862cbac8f63SCaesar Wang if (IS_ERR(thermal->pclk)) { 8630d0a2bf6SDan Carpenter error = PTR_ERR(thermal->pclk); 864cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n", 865cbac8f63SCaesar Wang error); 866cbac8f63SCaesar Wang return error; 867cbac8f63SCaesar Wang } 868cbac8f63SCaesar Wang 869cbac8f63SCaesar Wang error = clk_prepare_enable(thermal->clk); 870cbac8f63SCaesar Wang if (error) { 871cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to enable converter clock: %d\n", 872cbac8f63SCaesar Wang error); 873cbac8f63SCaesar Wang return error; 874cbac8f63SCaesar Wang } 875cbac8f63SCaesar Wang 876cbac8f63SCaesar Wang error = clk_prepare_enable(thermal->pclk); 877cbac8f63SCaesar Wang if (error) { 878cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to enable pclk: %d\n", error); 879cbac8f63SCaesar Wang goto err_disable_clk; 880cbac8f63SCaesar Wang } 881cbac8f63SCaesar Wang 882cbac8f63SCaesar Wang rockchip_thermal_reset_controller(thermal->reset); 883cbac8f63SCaesar Wang 884cbac8f63SCaesar Wang error = rockchip_configure_from_dt(&pdev->dev, np, thermal); 885cbac8f63SCaesar Wang if (error) { 886cbac8f63SCaesar Wang dev_err(&pdev->dev, "failed to parse device tree data: %d\n", 887cbac8f63SCaesar Wang error); 888cbac8f63SCaesar Wang goto err_disable_pclk; 889cbac8f63SCaesar Wang } 890cbac8f63SCaesar Wang 891cbac8f63SCaesar Wang thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 892cbac8f63SCaesar Wang 8931d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 894cbac8f63SCaesar Wang error = rockchip_thermal_register_sensor(pdev, thermal, 8951d98b618SCaesar Wang &thermal->sensors[i], 8961d98b618SCaesar Wang thermal->chip->chn_id[i]); 897cbac8f63SCaesar Wang if (error) { 898cbac8f63SCaesar Wang dev_err(&pdev->dev, 8991d98b618SCaesar Wang "failed to register sensor[%d] : error = %d\n", 9001d98b618SCaesar Wang i, error); 9011d98b618SCaesar Wang for (j = 0; j < i; j++) 9021d98b618SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, 9031d98b618SCaesar Wang thermal->sensors[j].tzd); 904cbac8f63SCaesar Wang goto err_disable_pclk; 905cbac8f63SCaesar Wang } 906cbac8f63SCaesar Wang } 907cbac8f63SCaesar Wang 908cbac8f63SCaesar Wang error = devm_request_threaded_irq(&pdev->dev, irq, NULL, 909cbac8f63SCaesar Wang &rockchip_thermal_alarm_irq_thread, 910cbac8f63SCaesar Wang IRQF_ONESHOT, 911cbac8f63SCaesar Wang "rockchip_thermal", thermal); 912cbac8f63SCaesar Wang if (error) { 913cbac8f63SCaesar Wang dev_err(&pdev->dev, 914cbac8f63SCaesar Wang "failed to request tsadc irq: %d\n", error); 9151d98b618SCaesar Wang goto err_unregister_sensor; 916cbac8f63SCaesar Wang } 917cbac8f63SCaesar Wang 918cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, true); 919cbac8f63SCaesar Wang 9201d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 921cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 922cbac8f63SCaesar Wang 923cbac8f63SCaesar Wang platform_set_drvdata(pdev, thermal); 924cbac8f63SCaesar Wang 925cbac8f63SCaesar Wang return 0; 926cbac8f63SCaesar Wang 9271d98b618SCaesar Wang err_unregister_sensor: 9281d98b618SCaesar Wang while (i--) 9291d98b618SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, 9301d98b618SCaesar Wang thermal->sensors[i].tzd); 9311d98b618SCaesar Wang 932cbac8f63SCaesar Wang err_disable_pclk: 933cbac8f63SCaesar Wang clk_disable_unprepare(thermal->pclk); 934cbac8f63SCaesar Wang err_disable_clk: 935cbac8f63SCaesar Wang clk_disable_unprepare(thermal->clk); 936cbac8f63SCaesar Wang 937cbac8f63SCaesar Wang return error; 938cbac8f63SCaesar Wang } 939cbac8f63SCaesar Wang 940cbac8f63SCaesar Wang static int rockchip_thermal_remove(struct platform_device *pdev) 941cbac8f63SCaesar Wang { 942cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 943cbac8f63SCaesar Wang int i; 944cbac8f63SCaesar Wang 9451d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 946cbac8f63SCaesar Wang struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; 947cbac8f63SCaesar Wang 948cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(sensor, false); 949cbac8f63SCaesar Wang thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); 950cbac8f63SCaesar Wang } 951cbac8f63SCaesar Wang 952cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, false); 953cbac8f63SCaesar Wang 954cbac8f63SCaesar Wang clk_disable_unprepare(thermal->pclk); 955cbac8f63SCaesar Wang clk_disable_unprepare(thermal->clk); 956cbac8f63SCaesar Wang 957cbac8f63SCaesar Wang return 0; 958cbac8f63SCaesar Wang } 959cbac8f63SCaesar Wang 960cbac8f63SCaesar Wang static int __maybe_unused rockchip_thermal_suspend(struct device *dev) 961cbac8f63SCaesar Wang { 962cbac8f63SCaesar Wang struct platform_device *pdev = to_platform_device(dev); 963cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 964cbac8f63SCaesar Wang int i; 965cbac8f63SCaesar Wang 9661d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 967cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], false); 968cbac8f63SCaesar Wang 969cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, false); 970cbac8f63SCaesar Wang 971cbac8f63SCaesar Wang clk_disable(thermal->pclk); 972cbac8f63SCaesar Wang clk_disable(thermal->clk); 973cbac8f63SCaesar Wang 9747e38a5b1SCaesar Wang pinctrl_pm_select_sleep_state(dev); 9757e38a5b1SCaesar Wang 976cbac8f63SCaesar Wang return 0; 977cbac8f63SCaesar Wang } 978cbac8f63SCaesar Wang 979cbac8f63SCaesar Wang static int __maybe_unused rockchip_thermal_resume(struct device *dev) 980cbac8f63SCaesar Wang { 981cbac8f63SCaesar Wang struct platform_device *pdev = to_platform_device(dev); 982cbac8f63SCaesar Wang struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 983cbac8f63SCaesar Wang int i; 984cbac8f63SCaesar Wang int error; 985cbac8f63SCaesar Wang 986cbac8f63SCaesar Wang error = clk_enable(thermal->clk); 987cbac8f63SCaesar Wang if (error) 988cbac8f63SCaesar Wang return error; 989cbac8f63SCaesar Wang 990cbac8f63SCaesar Wang error = clk_enable(thermal->pclk); 991cbac8f63SCaesar Wang if (error) 992cbac8f63SCaesar Wang return error; 993cbac8f63SCaesar Wang 994cbac8f63SCaesar Wang rockchip_thermal_reset_controller(thermal->reset); 995cbac8f63SCaesar Wang 996cbac8f63SCaesar Wang thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 997cbac8f63SCaesar Wang 9981d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) { 9991d98b618SCaesar Wang int id = thermal->sensors[i].id; 1000cbac8f63SCaesar Wang 1001cbac8f63SCaesar Wang thermal->chip->set_tshut_mode(id, thermal->regs, 1002cbac8f63SCaesar Wang thermal->tshut_mode); 1003ce74110dSCaesar Wang thermal->chip->set_tshut_temp(thermal->chip->table, 1004ce74110dSCaesar Wang id, thermal->regs, 1005cbac8f63SCaesar Wang thermal->tshut_temp); 1006cbac8f63SCaesar Wang } 1007cbac8f63SCaesar Wang 1008cbac8f63SCaesar Wang thermal->chip->control(thermal->regs, true); 1009cbac8f63SCaesar Wang 10101d98b618SCaesar Wang for (i = 0; i < thermal->chip->chn_num; i++) 1011cbac8f63SCaesar Wang rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 1012cbac8f63SCaesar Wang 10137e38a5b1SCaesar Wang pinctrl_pm_select_default_state(dev); 10147e38a5b1SCaesar Wang 1015cbac8f63SCaesar Wang return 0; 1016cbac8f63SCaesar Wang } 1017cbac8f63SCaesar Wang 1018cbac8f63SCaesar Wang static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops, 1019cbac8f63SCaesar Wang rockchip_thermal_suspend, rockchip_thermal_resume); 1020cbac8f63SCaesar Wang 1021cbac8f63SCaesar Wang static struct platform_driver rockchip_thermal_driver = { 1022cbac8f63SCaesar Wang .driver = { 1023cbac8f63SCaesar Wang .name = "rockchip-thermal", 1024cbac8f63SCaesar Wang .pm = &rockchip_thermal_pm_ops, 1025cbac8f63SCaesar Wang .of_match_table = of_rockchip_thermal_match, 1026cbac8f63SCaesar Wang }, 1027cbac8f63SCaesar Wang .probe = rockchip_thermal_probe, 1028cbac8f63SCaesar Wang .remove = rockchip_thermal_remove, 1029cbac8f63SCaesar Wang }; 1030cbac8f63SCaesar Wang 1031cbac8f63SCaesar Wang module_platform_driver(rockchip_thermal_driver); 1032cbac8f63SCaesar Wang 1033cbac8f63SCaesar Wang MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver"); 1034cbac8f63SCaesar Wang MODULE_AUTHOR("Rockchip, Inc."); 1035cbac8f63SCaesar Wang MODULE_LICENSE("GPL v2"); 1036cbac8f63SCaesar Wang MODULE_ALIAS("platform:rockchip-thermal"); 1037