···1111 "samsung,exynos5420-tmu" for TMU channel 0, 1 on Exynos54201212 "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 41313 Exynos5420 (Must pass triminfo base and triminfo clock)1414+ "samsung,exynos5433-tmu"1415 "samsung,exynos5440-tmu"1516 "samsung,exynos7-tmu"1617- interrupt-parent : The phandle for the interrupt controller···4140 for current TMU channel4241 -- "tmu_sclk" clock for functional operation of the current TMU4342 channel4444-- vtmu-supply: This entry is optional and provides the regulator node supplying4545- voltage to TMU. If needed this entry can be placed inside4646- board/platform specific dts file.4343+4444+The Exynos TMU supports generating interrupts when reaching given4545+temperature thresholds. Number of supported thermal trip points depends4646+on the SoC (only first trip points defined in DT will be configured):4747+ - most of SoC: 44848+ - samsung,exynos5433-tmu: 84949+ - samsung,exynos7-tmu: 85050+4751Following properties are mandatory (depending on SoC):4852- samsung,tmu_gain: Gain value for internal TMU operation.4953- samsung,tmu_reference_voltage: Value of TMU IP block's reference voltage···6155- samsung,tmu_second_point_trim: Second point trimming value6256- samsung,tmu_default_temp_offset: Default temperature offset6357- samsung,tmu_cal_type: Callibration type5858+5959+** Optional properties:6060+6161+- vtmu-supply: This entry is optional and provides the regulator node supplying6262+ voltage to TMU. If needed this entry can be placed inside6363+ board/platform specific dts file.64646565Example 1):6666
···11+* Mediatek Thermal22+33+This describes the device tree binding for the Mediatek thermal controller44+which measures the on-SoC temperatures. This device does not have its own ADC,55+instead it directly controls the AUXADC via AHB bus accesses. For this reason66+this device needs phandles to the AUXADC. Also it controls a mux in the77+apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS88+is also needed.99+1010+Required properties:1111+- compatible: "mediatek,mt8173-thermal"1212+- reg: Address range of the thermal controller1313+- interrupts: IRQ for the thermal controller1414+- clocks, clock-names: Clocks needed for the thermal controller. required1515+ clocks are:1616+ "therm": Main clock needed for register access1717+ "auxadc": The AUXADC clock1818+- resets: Reference to the reset controller controlling the thermal controller.1919+- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses2020+- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller.2121+- #thermal-sensor-cells : Should be 0. See ./thermal.txt for a description.2222+2323+Optional properties:2424+- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If2525+ unspecified default values shall be used.2626+- nvmem-cell-names: Should be "calibration-data"2727+2828+Example:2929+3030+ thermal: thermal@1100b000 {3131+ #thermal-sensor-cells = <1>;3232+ compatible = "mediatek,mt8173-thermal";3333+ reg = <0 0x1100b000 0 0x1000>;3434+ interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;3535+ clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;3636+ clock-names = "therm", "auxadc";3737+ resets = <&pericfg MT8173_PERI_THERM_SW_RST>;3838+ reset-names = "therm";3939+ mediatek,auxadc = <&auxadc>;4040+ mediatek,apmixedsys = <&apmixedsys>;4141+ nvmem-cells = <&thermal_calibration_data>;4242+ nvmem-cell-names = "calibration-data";4343+ };
+68
Documentation/thermal/sysfs-api.txt
···7272 It deletes the corresponding entry form /sys/class/thermal folder and7373 unbind all the thermal cooling devices it uses.74747575+1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register(7676+ struct device *dev, int sensor_id, void *data,7777+ const struct thermal_zone_of_device_ops *ops)7878+7979+ This interface adds a new sensor to a DT thermal zone.8080+ This function will search the list of thermal zones described in8181+ device tree and look for the zone that refer to the sensor device8282+ pointed by dev->of_node as temperature providers. For the zone8383+ pointing to the sensor node, the sensor will be added to the DT8484+ thermal zone device.8585+8686+ The parameters for this interface are:8787+ dev: Device node of sensor containing valid node pointer in8888+ dev->of_node.8989+ sensor_id: a sensor identifier, in case the sensor IP has more9090+ than one sensors9191+ data: a private pointer (owned by the caller) that will be9292+ passed back, when a temperature reading is needed.9393+ ops: struct thermal_zone_of_device_ops *.9494+9595+ get_temp: a pointer to a function that reads the9696+ sensor temperature. This is mandatory9797+ callback provided by sensor driver.9898+ get_trend: a pointer to a function that reads the9999+ sensor temperature trend.100100+ set_emul_temp: a pointer to a function that sets101101+ sensor emulated temperature.102102+ The thermal zone temperature is provided by the get_temp() function103103+ pointer of thermal_zone_of_device_ops. When called, it will104104+ have the private pointer @data back.105105+106106+ It returns error pointer if fails otherwise valid thermal zone device107107+ handle. Caller should check the return handle with IS_ERR() for finding108108+ whether success or not.109109+110110+1.1.4 void thermal_zone_of_sensor_unregister(struct device *dev,111111+ struct thermal_zone_device *tzd)112112+113113+ This interface unregisters a sensor from a DT thermal zone which was114114+ successfully added by interface thermal_zone_of_sensor_register().115115+ This function removes the sensor callbacks and private data from the116116+ thermal zone device registered with thermal_zone_of_sensor_register()117117+ interface. It will also silent the zone by remove the .get_temp() and118118+ get_trend() thermal zone device callbacks.119119+120120+1.1.5 struct thermal_zone_device *devm_thermal_zone_of_sensor_register(121121+ struct device *dev, int sensor_id,122122+ void *data, const struct thermal_zone_of_device_ops *ops)123123+124124+ This interface is resource managed version of125125+ thermal_zone_of_sensor_register().126126+ All details of thermal_zone_of_sensor_register() described in127127+ section 1.1.3 is applicable here.128128+ The benefit of using this interface to register sensor is that it129129+ is not require to explicitly call thermal_zone_of_sensor_unregister()130130+ in error path or during driver unbinding as this is done by driver131131+ resource manager.132132+133133+1.1.6 void devm_thermal_zone_of_sensor_unregister(struct device *dev,134134+ struct thermal_zone_device *tzd)135135+136136+ This interface is resource managed version of137137+ thermal_zone_of_sensor_unregister().138138+ All details of thermal_zone_of_sensor_unregister() described in139139+ section 1.1.4 is applicable here.140140+ Normally this function will not need to be called and the resource141141+ management code will ensure that the resource is freed.142142+751431.2 thermal cooling device interface761441.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,77145 void *devdata, struct thermal_cooling_device_ops *)
+19-2
drivers/thermal/Kconfig
···178178config HISI_THERMAL179179 tristate "Hisilicon thermal driver"180180 depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST181181+ depends on HAS_IOMEM181182 help182183 Enable this to plug hisilicon's thermal sensor driver into the Linux183184 thermal framework. cpufreq is used as the cooling device to throttle···198197config SPEAR_THERMAL199198 tristate "SPEAr thermal sensor driver"200199 depends on PLAT_SPEAR || COMPILE_TEST200200+ depends on HAS_IOMEM201201 depends on OF202202 help203203 Enable this to plug the SPEAr thermal sensor driver into the Linux···208206 tristate "Rockchip thermal driver"209207 depends on ARCH_ROCKCHIP || COMPILE_TEST210208 depends on RESET_CONTROLLER209209+ depends on HAS_IOMEM211210 help212211 Rockchip thermal driver provides support for Temperature sensor213212 ADC (TS-ADC) found on Rockchip SoCs. It supports one critical···217214218215config RCAR_THERMAL219216 tristate "Renesas R-Car thermal driver"220220- depends on ARCH_SHMOBILE || COMPILE_TEST217217+ depends on ARCH_RENESAS || COMPILE_TEST221218 depends on HAS_IOMEM222219 help223220 Enable this to plug the R-Car thermal sensor driver into the Linux···226223config KIRKWOOD_THERMAL227224 tristate "Temperature sensor on Marvell Kirkwood SoCs"228225 depends on MACH_KIRKWOOD || COMPILE_TEST226226+ depends on HAS_IOMEM229227 depends on OF230228 help231229 Support for the Kirkwood thermal sensor driver into the Linux thermal···235231config DOVE_THERMAL236232 tristate "Temperature sensor on Marvell Dove SoCs"237233 depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST234234+ depends on HAS_IOMEM238235 depends on OF239236 help240237 Support for the Dove thermal sensor driver in the Linux thermal···254249config ARMADA_THERMAL255250 tristate "Armada 370/XP thermal management"256251 depends on ARCH_MVEBU || COMPILE_TEST252252+ depends on HAS_IOMEM257253 depends on OF258254 help259255 Enable this option if you want to have support for thermal management···272266273267config DB8500_CPUFREQ_COOLING274268 tristate "DB8500 cpufreq cooling"275275- depends on ARCH_U8500269269+ depends on ARCH_U8500 || COMPILE_TEST270270+ depends on HAS_IOMEM276271 depends on CPU_THERMAL277272 default y278273 help···372365 Thermal reporting device will provide temperature reading,373366 programmable trip points and other information.374367368368+config MTK_THERMAL369369+ tristate "Temperature sensor driver for mediatek SoCs"370370+ depends on ARCH_MEDIATEK || COMPILE_TEST371371+ depends on HAS_IOMEM372372+ default y373373+ help374374+ Enable this option if you want to have support for thermal management375375+ controller present in Mediatek SoCs376376+375377menu "Texas Instruments thermal drivers"376378depends on ARCH_HAS_BANDGAP || COMPILE_TEST379379+depends on HAS_IOMEM377380source "drivers/thermal/ti-soc-thermal/Kconfig"378381endmenu379382
···11+/*22+ * Copyright (c) 2015 MediaTek Inc.33+ * Author: Hanyi Wu <hanyi.wu@mediatek.com>44+ * Sascha Hauer <s.hauer@pengutronix.de>55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+#include <linux/clk.h>1717+#include <linux/delay.h>1818+#include <linux/interrupt.h>1919+#include <linux/kernel.h>2020+#include <linux/module.h>2121+#include <linux/nvmem-consumer.h>2222+#include <linux/of.h>2323+#include <linux/of_address.h>2424+#include <linux/platform_device.h>2525+#include <linux/slab.h>2626+#include <linux/io.h>2727+#include <linux/thermal.h>2828+#include <linux/reset.h>2929+#include <linux/types.h>3030+#include <linux/nvmem-consumer.h>3131+3232+/* AUXADC Registers */3333+#define AUXADC_CON0_V 0x0003434+#define AUXADC_CON1_V 0x0043535+#define AUXADC_CON1_SET_V 0x0083636+#define AUXADC_CON1_CLR_V 0x00c3737+#define AUXADC_CON2_V 0x0103838+#define AUXADC_DATA(channel) (0x14 + (channel) * 4)3939+#define AUXADC_MISC_V 0x0944040+4141+#define AUXADC_CON1_CHANNEL(x) BIT(x)4242+4343+#define APMIXED_SYS_TS_CON1 0x6044444+4545+/* Thermal Controller Registers */4646+#define TEMP_MONCTL0 0x0004747+#define TEMP_MONCTL1 0x0044848+#define TEMP_MONCTL2 0x0084949+#define TEMP_MONIDET0 0x0145050+#define TEMP_MONIDET1 0x0185151+#define TEMP_MSRCTL0 0x0385252+#define TEMP_AHBPOLL 0x0405353+#define TEMP_AHBTO 0x0445454+#define TEMP_ADCPNP0 0x0485555+#define TEMP_ADCPNP1 0x04c5656+#define TEMP_ADCPNP2 0x0505757+#define TEMP_ADCPNP3 0x0b45858+5959+#define TEMP_ADCMUX 0x0546060+#define TEMP_ADCEN 0x0606161+#define TEMP_PNPMUXADDR 0x0646262+#define TEMP_ADCMUXADDR 0x0686363+#define TEMP_ADCENADDR 0x0746464+#define TEMP_ADCVALIDADDR 0x0786565+#define TEMP_ADCVOLTADDR 0x07c6666+#define TEMP_RDCTRL 0x0806767+#define TEMP_ADCVALIDMASK 0x0846868+#define TEMP_ADCVOLTAGESHIFT 0x0886969+#define TEMP_ADCWRITECTRL 0x08c7070+#define TEMP_MSR0 0x0907171+#define TEMP_MSR1 0x0947272+#define TEMP_MSR2 0x0987373+#define TEMP_MSR3 0x0B87474+7575+#define TEMP_SPARE0 0x0f07676+7777+#define PTPCORESEL 0x4007878+7979+#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)8080+8181+#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)8282+#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)8383+8484+#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)8585+8686+#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)8787+#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)8888+8989+#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)9090+#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)9191+9292+#define MT8173_TS1 09393+#define MT8173_TS2 19494+#define MT8173_TS3 29595+#define MT8173_TS4 39696+#define MT8173_TSABB 49797+9898+/* AUXADC channel 11 is used for the temperature sensors */9999+#define MT8173_TEMP_AUXADC_CHANNEL 11100100+101101+/* The total number of temperature sensors in the MT8173 */102102+#define MT8173_NUM_SENSORS 5103103+104104+/* The number of banks in the MT8173 */105105+#define MT8173_NUM_ZONES 4106106+107107+/* The number of sensing points per bank */108108+#define MT8173_NUM_SENSORS_PER_ZONE 4109109+110110+/* Layout of the fuses providing the calibration data */111111+#define MT8173_CALIB_BUF0_VALID BIT(0)112112+#define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff)113113+#define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff)114114+#define MT8173_CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff)115115+#define MT8173_CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff)116116+#define MT8173_CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff)117117+#define MT8173_CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff)118118+#define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f)119119+#define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f)120120+121121+#define THERMAL_NAME "mtk-thermal"122122+123123+struct mtk_thermal;124124+125125+struct mtk_thermal_bank {126126+ struct mtk_thermal *mt;127127+ int id;128128+};129129+130130+struct mtk_thermal {131131+ struct device *dev;132132+ void __iomem *thermal_base;133133+134134+ struct clk *clk_peri_therm;135135+ struct clk *clk_auxadc;136136+137137+ struct mtk_thermal_bank banks[MT8173_NUM_ZONES];138138+139139+ /* lock: for getting and putting banks */140140+ struct mutex lock;141141+142142+ /* Calibration values */143143+ s32 adc_ge;144144+ s32 degc_cali;145145+ s32 o_slope;146146+ s32 vts[MT8173_NUM_SENSORS];147147+148148+ struct thermal_zone_device *tzd;149149+};150150+151151+struct mtk_thermal_bank_cfg {152152+ unsigned int num_sensors;153153+ unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE];154154+};155155+156156+static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };157157+158158+/*159159+ * The MT8173 thermal controller has four banks. Each bank can read up to160160+ * four temperature sensors simultaneously. The MT8173 has a total of 5161161+ * temperature sensors. We use each bank to measure a certain area of the162162+ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple163163+ * areas, hence is used in different banks.164164+ *165165+ * The thermal core only gets the maximum temperature of all banks, so166166+ * the bank concept wouldn't be necessary here. However, the SVS (Smart167167+ * Voltage Scaling) unit makes its decisions based on the same bank168168+ * data, and this indeed needs the temperatures of the individual banks169169+ * for making better decisions.170170+ */171171+static const struct mtk_thermal_bank_cfg bank_data[] = {172172+ {173173+ .num_sensors = 2,174174+ .sensors = { MT8173_TS2, MT8173_TS3 },175175+ }, {176176+ .num_sensors = 2,177177+ .sensors = { MT8173_TS2, MT8173_TS4 },178178+ }, {179179+ .num_sensors = 3,180180+ .sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB },181181+ }, {182182+ .num_sensors = 1,183183+ .sensors = { MT8173_TS2 },184184+ },185185+};186186+187187+struct mtk_thermal_sense_point {188188+ int msr;189189+ int adcpnp;190190+};191191+192192+static const struct mtk_thermal_sense_point193193+ sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = {194194+ {195195+ .msr = TEMP_MSR0,196196+ .adcpnp = TEMP_ADCPNP0,197197+ }, {198198+ .msr = TEMP_MSR1,199199+ .adcpnp = TEMP_ADCPNP1,200200+ }, {201201+ .msr = TEMP_MSR2,202202+ .adcpnp = TEMP_ADCPNP2,203203+ }, {204204+ .msr = TEMP_MSR3,205205+ .adcpnp = TEMP_ADCPNP3,206206+ },207207+};208208+209209+/**210210+ * raw_to_mcelsius - convert a raw ADC value to mcelsius211211+ * @mt: The thermal controller212212+ * @raw: raw ADC value213213+ *214214+ * This converts the raw ADC value to mcelsius using the SoC specific215215+ * calibration constants216216+ */217217+static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw)218218+{219219+ s32 tmp;220220+221221+ raw &= 0xfff;222222+223223+ tmp = 203450520 << 3;224224+ tmp /= 165 + mt->o_slope;225225+ tmp /= 10000 + mt->adc_ge;226226+ tmp *= raw - mt->vts[sensno] - 3350;227227+ tmp >>= 3;228228+229229+ return mt->degc_cali * 500 - tmp;230230+}231231+232232+/**233233+ * mtk_thermal_get_bank - get bank234234+ * @bank: The bank235235+ *236236+ * The bank registers are banked, we have to select a bank in the237237+ * PTPCORESEL register to access it.238238+ */239239+static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)240240+{241241+ struct mtk_thermal *mt = bank->mt;242242+ u32 val;243243+244244+ mutex_lock(&mt->lock);245245+246246+ val = readl(mt->thermal_base + PTPCORESEL);247247+ val &= ~0xf;248248+ val |= bank->id;249249+ writel(val, mt->thermal_base + PTPCORESEL);250250+}251251+252252+/**253253+ * mtk_thermal_put_bank - release bank254254+ * @bank: The bank255255+ *256256+ * release a bank previously taken with mtk_thermal_get_bank,257257+ */258258+static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)259259+{260260+ struct mtk_thermal *mt = bank->mt;261261+262262+ mutex_unlock(&mt->lock);263263+}264264+265265+/**266266+ * mtk_thermal_bank_temperature - get the temperature of a bank267267+ * @bank: The bank268268+ *269269+ * The temperature of a bank is considered the maximum temperature of270270+ * the sensors associated to the bank.271271+ */272272+static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)273273+{274274+ struct mtk_thermal *mt = bank->mt;275275+ int i, temp = INT_MIN, max = INT_MIN;276276+ u32 raw;277277+278278+ for (i = 0; i < bank_data[bank->id].num_sensors; i++) {279279+ raw = readl(mt->thermal_base + sensing_points[i].msr);280280+281281+ temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw);282282+283283+ /*284284+ * The first read of a sensor often contains very high bogus285285+ * temperature value. Filter these out so that the system does286286+ * not immediately shut down.287287+ */288288+ if (temp > 200000)289289+ temp = 0;290290+291291+ if (temp > max)292292+ max = temp;293293+ }294294+295295+ return max;296296+}297297+298298+static int mtk_read_temp(void *data, int *temperature)299299+{300300+ struct mtk_thermal *mt = data;301301+ int i;302302+ int tempmax = INT_MIN;303303+304304+ for (i = 0; i < MT8173_NUM_ZONES; i++) {305305+ struct mtk_thermal_bank *bank = &mt->banks[i];306306+307307+ mtk_thermal_get_bank(bank);308308+309309+ tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));310310+311311+ mtk_thermal_put_bank(bank);312312+ }313313+314314+ *temperature = tempmax;315315+316316+ return 0;317317+}318318+319319+static const struct thermal_zone_of_device_ops mtk_thermal_ops = {320320+ .get_temp = mtk_read_temp,321321+};322322+323323+static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,324324+ u32 apmixed_phys_base, u32 auxadc_phys_base)325325+{326326+ struct mtk_thermal_bank *bank = &mt->banks[num];327327+ const struct mtk_thermal_bank_cfg *cfg = &bank_data[num];328328+ int i;329329+330330+ bank->id = num;331331+ bank->mt = mt;332332+333333+ mtk_thermal_get_bank(bank);334334+335335+ /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */336336+ writel(TEMP_MONCTL1_PERIOD_UNIT(12), mt->thermal_base + TEMP_MONCTL1);337337+338338+ /*339339+ * filt interval is 1 * 46.540us = 46.54us,340340+ * sen interval is 429 * 46.540us = 19.96ms341341+ */342342+ writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |343343+ TEMP_MONCTL2_SENSOR_INTERVAL(429),344344+ mt->thermal_base + TEMP_MONCTL2);345345+346346+ /* poll is set to 10u */347347+ writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),348348+ mt->thermal_base + TEMP_AHBPOLL);349349+350350+ /* temperature sampling control, 1 sample */351351+ writel(0x0, mt->thermal_base + TEMP_MSRCTL0);352352+353353+ /* exceed this polling time, IRQ would be inserted */354354+ writel(0xffffffff, mt->thermal_base + TEMP_AHBTO);355355+356356+ /* number of interrupts per event, 1 is enough */357357+ writel(0x0, mt->thermal_base + TEMP_MONIDET0);358358+ writel(0x0, mt->thermal_base + TEMP_MONIDET1);359359+360360+ /*361361+ * The MT8173 thermal controller does not have its own ADC. Instead it362362+ * uses AHB bus accesses to control the AUXADC. To do this the thermal363363+ * controller has to be programmed with the physical addresses of the364364+ * AUXADC registers and with the various bit positions in the AUXADC.365365+ * Also the thermal controller controls a mux in the APMIXEDSYS register366366+ * space.367367+ */368368+369369+ /*370370+ * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)371371+ * automatically by hw372372+ */373373+ writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX);374374+375375+ /* AHB address for auxadc mux selection */376376+ writel(auxadc_phys_base + AUXADC_CON1_CLR_V,377377+ mt->thermal_base + TEMP_ADCMUXADDR);378378+379379+ /* AHB address for pnp sensor mux selection */380380+ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,381381+ mt->thermal_base + TEMP_PNPMUXADDR);382382+383383+ /* AHB value for auxadc enable */384384+ writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN);385385+386386+ /* AHB address for auxadc enable (channel 0 immediate mode selected) */387387+ writel(auxadc_phys_base + AUXADC_CON1_SET_V,388388+ mt->thermal_base + TEMP_ADCENADDR);389389+390390+ /* AHB address for auxadc valid bit */391391+ writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),392392+ mt->thermal_base + TEMP_ADCVALIDADDR);393393+394394+ /* AHB address for auxadc voltage output */395395+ writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL),396396+ mt->thermal_base + TEMP_ADCVOLTADDR);397397+398398+ /* read valid & voltage are at the same register */399399+ writel(0x0, mt->thermal_base + TEMP_RDCTRL);400400+401401+ /* indicate where the valid bit is */402402+ writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),403403+ mt->thermal_base + TEMP_ADCVALIDMASK);404404+405405+ /* no shift */406406+ writel(0x0, mt->thermal_base + TEMP_ADCVOLTAGESHIFT);407407+408408+ /* enable auxadc mux write transaction */409409+ writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,410410+ mt->thermal_base + TEMP_ADCWRITECTRL);411411+412412+ for (i = 0; i < cfg->num_sensors; i++)413413+ writel(sensor_mux_values[cfg->sensors[i]],414414+ mt->thermal_base + sensing_points[i].adcpnp);415415+416416+ writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0);417417+418418+ writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |419419+ TEMP_ADCWRITECTRL_ADC_MUX_WRITE,420420+ mt->thermal_base + TEMP_ADCWRITECTRL);421421+422422+ mtk_thermal_put_bank(bank);423423+}424424+425425+static u64 of_get_phys_base(struct device_node *np)426426+{427427+ u64 size64;428428+ const __be32 *regaddr_p;429429+430430+ regaddr_p = of_get_address(np, 0, &size64, NULL);431431+ if (!regaddr_p)432432+ return OF_BAD_ADDR;433433+434434+ return of_translate_address(np, regaddr_p);435435+}436436+437437+static int mtk_thermal_get_calibration_data(struct device *dev,438438+ struct mtk_thermal *mt)439439+{440440+ struct nvmem_cell *cell;441441+ u32 *buf;442442+ size_t len;443443+ int i, ret = 0;444444+445445+ /* Start with default values */446446+ mt->adc_ge = 512;447447+ for (i = 0; i < MT8173_NUM_SENSORS; i++)448448+ mt->vts[i] = 260;449449+ mt->degc_cali = 40;450450+ mt->o_slope = 0;451451+452452+ cell = nvmem_cell_get(dev, "calibration-data");453453+ if (IS_ERR(cell)) {454454+ if (PTR_ERR(cell) == -EPROBE_DEFER)455455+ return PTR_ERR(cell);456456+ return 0;457457+ }458458+459459+ buf = (u32 *)nvmem_cell_read(cell, &len);460460+461461+ nvmem_cell_put(cell);462462+463463+ if (IS_ERR(buf))464464+ return PTR_ERR(buf);465465+466466+ if (len < 3 * sizeof(u32)) {467467+ dev_warn(dev, "invalid calibration data\n");468468+ ret = -EINVAL;469469+ goto out;470470+ }471471+472472+ if (buf[0] & MT8173_CALIB_BUF0_VALID) {473473+ mt->adc_ge = MT8173_CALIB_BUF1_ADC_GE(buf[1]);474474+ mt->vts[MT8173_TS1] = MT8173_CALIB_BUF0_VTS_TS1(buf[0]);475475+ mt->vts[MT8173_TS2] = MT8173_CALIB_BUF0_VTS_TS2(buf[0]);476476+ mt->vts[MT8173_TS3] = MT8173_CALIB_BUF1_VTS_TS3(buf[1]);477477+ mt->vts[MT8173_TS4] = MT8173_CALIB_BUF2_VTS_TS4(buf[2]);478478+ mt->vts[MT8173_TSABB] = MT8173_CALIB_BUF2_VTS_TSABB(buf[2]);479479+ mt->degc_cali = MT8173_CALIB_BUF0_DEGC_CALI(buf[0]);480480+ mt->o_slope = MT8173_CALIB_BUF0_O_SLOPE(buf[0]);481481+ } else {482482+ dev_info(dev, "Device not calibrated, using default calibration values\n");483483+ }484484+485485+out:486486+ kfree(buf);487487+488488+ return ret;489489+}490490+491491+static int mtk_thermal_probe(struct platform_device *pdev)492492+{493493+ int ret, i;494494+ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;495495+ struct mtk_thermal *mt;496496+ struct resource *res;497497+ u64 auxadc_phys_base, apmixed_phys_base;498498+499499+ mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);500500+ if (!mt)501501+ return -ENOMEM;502502+503503+ mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");504504+ if (IS_ERR(mt->clk_peri_therm))505505+ return PTR_ERR(mt->clk_peri_therm);506506+507507+ mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");508508+ if (IS_ERR(mt->clk_auxadc))509509+ return PTR_ERR(mt->clk_auxadc);510510+511511+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);512512+ mt->thermal_base = devm_ioremap_resource(&pdev->dev, res);513513+ if (IS_ERR(mt->thermal_base))514514+ return PTR_ERR(mt->thermal_base);515515+516516+ ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);517517+ if (ret)518518+ return ret;519519+520520+ mutex_init(&mt->lock);521521+522522+ mt->dev = &pdev->dev;523523+524524+ auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);525525+ if (!auxadc) {526526+ dev_err(&pdev->dev, "missing auxadc node\n");527527+ return -ENODEV;528528+ }529529+530530+ auxadc_phys_base = of_get_phys_base(auxadc);531531+532532+ of_node_put(auxadc);533533+534534+ if (auxadc_phys_base == OF_BAD_ADDR) {535535+ dev_err(&pdev->dev, "Can't get auxadc phys address\n");536536+ return -EINVAL;537537+ }538538+539539+ apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);540540+ if (!apmixedsys) {541541+ dev_err(&pdev->dev, "missing apmixedsys node\n");542542+ return -ENODEV;543543+ }544544+545545+ apmixed_phys_base = of_get_phys_base(apmixedsys);546546+547547+ of_node_put(apmixedsys);548548+549549+ if (apmixed_phys_base == OF_BAD_ADDR) {550550+ dev_err(&pdev->dev, "Can't get auxadc phys address\n");551551+ return -EINVAL;552552+ }553553+554554+ ret = clk_prepare_enable(mt->clk_auxadc);555555+ if (ret) {556556+ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);557557+ return ret;558558+ }559559+560560+ ret = device_reset(&pdev->dev);561561+ if (ret)562562+ goto err_disable_clk_auxadc;563563+564564+ ret = clk_prepare_enable(mt->clk_peri_therm);565565+ if (ret) {566566+ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);567567+ goto err_disable_clk_auxadc;568568+ }569569+570570+ for (i = 0; i < MT8173_NUM_ZONES; i++)571571+ mtk_thermal_init_bank(mt, i, apmixed_phys_base,572572+ auxadc_phys_base);573573+574574+ platform_set_drvdata(pdev, mt);575575+576576+ mt->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, mt,577577+ &mtk_thermal_ops);578578+ if (IS_ERR(mt->tzd))579579+ goto err_register;580580+581581+ return 0;582582+583583+err_register:584584+ clk_disable_unprepare(mt->clk_peri_therm);585585+586586+err_disable_clk_auxadc:587587+ clk_disable_unprepare(mt->clk_auxadc);588588+589589+ return ret;590590+}591591+592592+static int mtk_thermal_remove(struct platform_device *pdev)593593+{594594+ struct mtk_thermal *mt = platform_get_drvdata(pdev);595595+596596+ thermal_zone_of_sensor_unregister(&pdev->dev, mt->tzd);597597+598598+ clk_disable_unprepare(mt->clk_peri_therm);599599+ clk_disable_unprepare(mt->clk_auxadc);600600+601601+ return 0;602602+}603603+604604+static const struct of_device_id mtk_thermal_of_match[] = {605605+ {606606+ .compatible = "mediatek,mt8173-thermal",607607+ }, {608608+ },609609+};610610+611611+static struct platform_driver mtk_thermal_driver = {612612+ .probe = mtk_thermal_probe,613613+ .remove = mtk_thermal_remove,614614+ .driver = {615615+ .name = THERMAL_NAME,616616+ .of_match_table = mtk_thermal_of_match,617617+ },618618+};619619+620620+module_platform_driver(mtk_thermal_driver);621621+622622+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");623623+MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");624624+MODULE_DESCRIPTION("Mediatek thermal driver");625625+MODULE_LICENSE("GPL v2");
+81
drivers/thermal/of-thermal.c
···555555}556556EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);557557558558+static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)559559+{560560+ thermal_zone_of_sensor_unregister(dev,561561+ *(struct thermal_zone_device **)res);562562+}563563+564564+static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,565565+ void *data)566566+{567567+ struct thermal_zone_device **r = res;568568+569569+ if (WARN_ON(!r || !*r))570570+ return 0;571571+572572+ return *r == data;573573+}574574+575575+/**576576+ * devm_thermal_zone_of_sensor_register - Resource managed version of577577+ * thermal_zone_of_sensor_register()578578+ * @dev: a valid struct device pointer of a sensor device. Must contain579579+ * a valid .of_node, for the sensor node.580580+ * @sensor_id: a sensor identifier, in case the sensor IP has more581581+ * than one sensors582582+ * @data: a private pointer (owned by the caller) that will be passed583583+ * back, when a temperature reading is needed.584584+ * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.585585+ *586586+ * Refer thermal_zone_of_sensor_register() for more details.587587+ *588588+ * Return: On success returns a valid struct thermal_zone_device,589589+ * otherwise, it returns a corresponding ERR_PTR(). Caller must590590+ * check the return value with help of IS_ERR() helper.591591+ * Registered hermal_zone_device device will automatically be592592+ * released when device is unbounded.593593+ */594594+struct thermal_zone_device *devm_thermal_zone_of_sensor_register(595595+ struct device *dev, int sensor_id,596596+ void *data, const struct thermal_zone_of_device_ops *ops)597597+{598598+ struct thermal_zone_device **ptr, *tzd;599599+600600+ ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),601601+ GFP_KERNEL);602602+ if (!ptr)603603+ return ERR_PTR(-ENOMEM);604604+605605+ tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);606606+ if (IS_ERR(tzd)) {607607+ devres_free(ptr);608608+ return tzd;609609+ }610610+611611+ *ptr = tzd;612612+ devres_add(dev, ptr);613613+614614+ return tzd;615615+}616616+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);617617+618618+/**619619+ * devm_thermal_zone_of_sensor_unregister - Resource managed version of620620+ * thermal_zone_of_sensor_unregister().621621+ * @dev: Device for which which resource was allocated.622622+ * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.623623+ *624624+ * This function removes the sensor callbacks and private data from the625625+ * thermal zone device registered with devm_thermal_zone_of_sensor_register()626626+ * API. It will also silent the zone by remove the .get_temp() and .get_trend()627627+ * thermal zone device callbacks.628628+ * Normally this function will not need to be called and the resource629629+ * management code will ensure that the resource is freed.630630+ */631631+void devm_thermal_zone_of_sensor_unregister(struct device *dev,632632+ struct thermal_zone_device *tzd)633633+{634634+ WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,635635+ devm_thermal_zone_of_sensor_match, tzd));636636+}637637+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);638638+558639/*** functions parsing device tree nodes ***/559640560641/**
+1-2
drivers/thermal/rcar_thermal.c
···430430 struct rcar_thermal_priv *priv;431431 struct device *dev = &pdev->dev;432432 struct resource *res, *irq;433433- const struct of_device_id *of_id = of_match_device(rcar_thermal_dt_ids, dev);434434- unsigned long of_data = (unsigned long)of_id->data;433433+ unsigned long of_data = (unsigned long)of_device_get_match_data(dev);435434 int mres = 0;436435 int i;437436 int ret = -ENODEV;
···11config EXYNOS_THERMAL22 tristate "Exynos thermal management unit driver"33 depends on THERMAL_OF44+ depends on HAS_IOMEM45 help56 If you say yes here you get support for the TMU (Thermal Management67 Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
+18-1
drivers/thermal/samsung/exynos_tmu.c
···184184 * @temp_error2: fused value of the second point trim.185185 * @regulator: pointer to the TMU regulator structure.186186 * @reg_conf: pointer to structure to register with core thermal.187187+ * @ntrip: number of supported trip points.187188 * @tmu_initialize: SoC specific TMU initialization method188189 * @tmu_control: SoC specific TMU control method189190 * @tmu_read: SoC specific TMU temperature read method···204203 u16 temp_error1, temp_error2;205204 struct regulator *regulator;206205 struct thermal_zone_device *tzd;206206+ unsigned int ntrip;207207208208 int (*tmu_initialize)(struct platform_device *pdev);209209 void (*tmu_control)(struct platform_device *pdev, bool on);···347345{348346 struct exynos_tmu_data *data = platform_get_drvdata(pdev);349347 int ret;348348+349349+ if (of_thermal_get_ntrips(data->tzd) > data->ntrip) {350350+ dev_info(&pdev->dev,351351+ "More trip points than supported by this TMU.\n");352352+ dev_info(&pdev->dev,353353+ "%d trip points should be configured in polling mode.\n",354354+ (of_thermal_get_ntrips(data->tzd) - data->ntrip));355355+ }350356351357 mutex_lock(&data->lock);352358 clk_enable(data->clk);···12201210 data->tmu_control = exynos4210_tmu_control;12211211 data->tmu_read = exynos4210_tmu_read;12221212 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;12131213+ data->ntrip = 4;12231214 break;12241215 case SOC_ARCH_EXYNOS3250:12251216 case SOC_ARCH_EXYNOS4412:···12331222 data->tmu_read = exynos4412_tmu_read;12341223 data->tmu_set_emulation = exynos4412_tmu_set_emulation;12351224 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;12251225+ data->ntrip = 4;12361226 break;12371227 case SOC_ARCH_EXYNOS5433:12381228 data->tmu_initialize = exynos5433_tmu_initialize;···12411229 data->tmu_read = exynos4412_tmu_read;12421230 data->tmu_set_emulation = exynos4412_tmu_set_emulation;12431231 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;12321232+ data->ntrip = 8;12441233 break;12451234 case SOC_ARCH_EXYNOS5440:12461235 data->tmu_initialize = exynos5440_tmu_initialize;···12491236 data->tmu_read = exynos5440_tmu_read;12501237 data->tmu_set_emulation = exynos5440_tmu_set_emulation;12511238 data->tmu_clear_irqs = exynos5440_tmu_clear_irqs;12391239+ data->ntrip = 4;12521240 break;12531241 case SOC_ARCH_EXYNOS7:12541242 data->tmu_initialize = exynos7_tmu_initialize;···12571243 data->tmu_read = exynos7_tmu_read;12581244 data->tmu_set_emulation = exynos4412_tmu_set_emulation;12591245 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;12461246+ data->ntrip = 8;12601247 break;12611248 default:12621249 dev_err(&pdev->dev, "Platform not supported\n");···13101295 * TODO: Add regulator as an SOC feature, so that regulator enable13111296 * is a compulsory call.13121297 */13131313- data->regulator = devm_regulator_get(&pdev->dev, "vtmu");12981298+ data->regulator = devm_regulator_get_optional(&pdev->dev, "vtmu");13141299 if (!IS_ERR(data->regulator)) {13151300 ret = regulator_enable(data->regulator);13161301 if (ret) {···13181303 return ret;13191304 }13201305 } else {13061306+ if (PTR_ERR(data->regulator) == -EPROBE_DEFER)13071307+ return -EPROBE_DEFER;13211308 dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");13221309 }13231310
···12651265int ti_bandgap_probe(struct platform_device *pdev)12661266{12671267 struct ti_bandgap *bgp;12681268- int clk_rate, ret = 0, i;12681268+ int clk_rate, ret, i;1269126912701270 bgp = ti_bandgap_build(pdev);12711271 if (IS_ERR(bgp)) {···12881288 }1289128912901290 bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);12911291- ret = IS_ERR(bgp->fclock);12921292- if (ret) {12911291+ if (IS_ERR(bgp->fclock)) {12931292 dev_err(&pdev->dev, "failed to request fclock reference\n");12941293 ret = PTR_ERR(bgp->fclock);12951294 goto free_irqs;12961295 }1297129612981297 bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);12991299- ret = IS_ERR(bgp->div_clk);13001300- if (ret) {12981298+ if (IS_ERR(bgp->div_clk)) {13011299 dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n");13021300 ret = PTR_ERR(bgp->div_clk);13031301 goto free_irqs;···13121314 * may not be accurate13131315 */13141316 val = ti_bandgap_readl(bgp, tsr->bgap_efuse);13151315- if (ret || !val)13171317+ if (!val)13161318 dev_info(&pdev->dev,13171319 "Non-trimmed BGAP, Temp not accurate\n");13181320 }