Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux

Pull thermal management update from Zhang Rui:
"Summary:

- of-thermal extension to allow drivers to register and use its
functionality in a better way, without exploiting thermal core.
From Lukasz Majewski.

- Fix a bug in intel_soc_dts_thermal driver which calls a sleep
function in interrupt handler. From Maurice Petallo.

- add a thermal UAPI header file for exporting the thermal generic
netlink information to user-space. From Florian Fainelli.

- First round of refactoring in Exynos driver. Bartlomiej and Lukasz
are attempting to make it lean and easier to understand.

- New thermal driver for Rockchip (rk3288), with support for DT
thermal. From Caesar Wang.

- New thermal driver for Nvidia, Tegra124 SOCTHERM driver, with
support for DT thermal. From Mikko Perttunen.

- New cooling device, based on common clock framework. From Eduardo
Valentin.

- a couple of small fixes in thermal core framework. From Srinivas
Pandruvada, Javi Merino, Luis Henriques.

- Dropping Armada A375-Z1 SoC thermal support as the chip is not in
the market, armada folks decided to drop its support.

- a couple of small fixes and cleanups in int340x thermal driver"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (58 commits)
thermal: provide an UAPI header file
Thermal/int340x: Clear the error value of the last acpi_bus_get_device() call
thermal/powerclamp: add id for braswell cpu
thermal: Intel SoC DTS: Don't do thermal zone update inside spin_lock
Thermal: fix platform_no_drv_owner.cocci warnings
Thermal/int340x: avoid unnecessary pointer casting
thermal: int3403: Delete a check before thermal_zone_device_unregister()
thermal/int3400: export uuids
thermal: of: Extend current of-thermal.c code to allow setting emulated temp
thermal: of: Extend of-thermal to export table of trip points
thermal: of: Rename struct __thermal_trip to struct thermal_trip
thermal: of: Extend of-thermal.c to provide check if trip point is valid
thermal: of: Extend of-thermal.c to provide number of trip points
thermal: Fix error path in thermal_init()
thermal: lock the thermal zone when switching governors
thermal: core: ignore invalid trip temperature
thermal: armada: Remove support for A375-Z1 SoC
thermal: rockchip: add driver for thermal
dt-bindings: document Rockchip thermal
thermal: exynos: remove exynos_tmu_data.h include
...

+2788 -859
-8
Documentation/devicetree/bindings/thermal/armada-thermal.txt
··· 5 5 - compatible: Should be set to one of the following: 6 6 marvell,armada370-thermal 7 7 marvell,armada375-thermal 8 - marvell,armada375-z1-thermal 9 8 marvell,armada380-thermal 10 9 marvell,armadaxp-thermal 11 - 12 - Note: As the name suggests, "marvell,armada375-z1-thermal" 13 - applies for the SoC Z1 stepping only. On such stepping 14 - some quirks need to be done and the register offset differs 15 - from the one in the A0 stepping. 16 - The operating system may auto-detect the SoC stepping and 17 - update the compatible and register offsets at runtime. 18 10 19 11 - reg: Device's register space. 20 12 Two entries are expected, see the examples below.
+68
Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
··· 1 + * Temperature Sensor ADC (TSADC) on rockchip SoCs 2 + 3 + Required properties: 4 + - compatible : "rockchip,rk3288-tsadc" 5 + - reg : physical base address of the controller and length of memory mapped 6 + region. 7 + - interrupts : The interrupt number to the cpu. The interrupt specifier format 8 + depends on the interrupt controller. 9 + - clocks : Must contain an entry for each entry in clock-names. 10 + - clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for 11 + the peripheral clock. 12 + - resets : Must contain an entry for each entry in reset-names. 13 + See ../reset/reset.txt for details. 14 + - reset-names : Must include the name "tsadc-apb". 15 + - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. 16 + - rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. 17 + - rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. 18 + - rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW 19 + 1:HIGH. 20 + 21 + Exiample: 22 + tsadc: tsadc@ff280000 { 23 + compatible = "rockchip,rk3288-tsadc"; 24 + reg = <0xff280000 0x100>; 25 + interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; 26 + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; 27 + clock-names = "tsadc", "apb_pclk"; 28 + resets = <&cru SRST_TSADC>; 29 + reset-names = "tsadc-apb"; 30 + pinctrl-names = "default"; 31 + pinctrl-0 = <&otp_out>; 32 + #thermal-sensor-cells = <1>; 33 + rockchip,hw-tshut-temp = <95000>; 34 + rockchip,hw-tshut-mode = <0>; 35 + rockchip,hw-tshut-polarity = <0>; 36 + }; 37 + 38 + Example: referring to thermal sensors: 39 + thermal-zones { 40 + cpu_thermal: cpu_thermal { 41 + polling-delay-passive = <1000>; /* milliseconds */ 42 + polling-delay = <5000>; /* milliseconds */ 43 + 44 + /* sensor ID */ 45 + thermal-sensors = <&tsadc 1>; 46 + 47 + trips { 48 + cpu_alert0: cpu_alert { 49 + temperature = <70000>; /* millicelsius */ 50 + hysteresis = <2000>; /* millicelsius */ 51 + type = "passive"; 52 + }; 53 + cpu_crit: cpu_crit { 54 + temperature = <90000>; /* millicelsius */ 55 + hysteresis = <2000>; /* millicelsius */ 56 + type = "critical"; 57 + }; 58 + }; 59 + 60 + cooling-maps { 61 + map0 { 62 + trip = <&cpu_alert0>; 63 + cooling-device = 64 + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; 65 + }; 66 + }; 67 + }; 68 + };
+53
Documentation/devicetree/bindings/thermal/tegra-soctherm.txt
··· 1 + Tegra124 SOCTHERM thermal management system 2 + 3 + The SOCTHERM IP block contains thermal sensors, support for polled 4 + or interrupt-based thermal monitoring, CPU and GPU throttling based 5 + on temperature trip points, and handling external overcurrent 6 + notifications. It is also used to manage emergency shutdown in an 7 + overheating situation. 8 + 9 + Required properties : 10 + - compatible : "nvidia,tegra124-soctherm". 11 + - reg : Should contain 1 entry: 12 + - SOCTHERM register set 13 + - interrupts : Defines the interrupt used by SOCTHERM 14 + - clocks : Must contain an entry for each entry in clock-names. 15 + See ../clocks/clock-bindings.txt for details. 16 + - clock-names : Must include the following entries: 17 + - tsensor 18 + - soctherm 19 + - resets : Must contain an entry for each entry in reset-names. 20 + See ../reset/reset.txt for details. 21 + - reset-names : Must include the following entries: 22 + - soctherm 23 + - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description 24 + of this property. See <dt-bindings/thermal/tegra124-soctherm.h> for a 25 + list of valid values when referring to thermal sensors. 26 + 27 + 28 + Example : 29 + 30 + soctherm@0,700e2000 { 31 + compatible = "nvidia,tegra124-soctherm"; 32 + reg = <0x0 0x700e2000 0x0 0x1000>; 33 + interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; 34 + clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, 35 + <&tegra_car TEGRA124_CLK_SOC_THERM>; 36 + clock-names = "tsensor", "soctherm"; 37 + resets = <&tegra_car 78>; 38 + reset-names = "soctherm"; 39 + 40 + #thermal-sensor-cells = <1>; 41 + }; 42 + 43 + Example: referring to thermal sensors : 44 + 45 + thermal-zones { 46 + cpu { 47 + polling-delay-passive = <1000>; 48 + polling-delay = <1000>; 49 + 50 + thermal-sensors = 51 + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; 52 + }; 53 + };
+1
MAINTAINERS
··· 9516 9516 S: Supported 9517 9517 F: drivers/thermal/ 9518 9518 F: include/linux/thermal.h 9519 + F: include/uapi/linux/thermal.h 9519 9520 F: include/linux/cpu_cooling.h 9520 9521 F: Documentation/devicetree/bindings/thermal/ 9521 9522
+44
arch/arm/boot/dts/tegra124-jetson-tk1.dts
··· 1942 1942 <&tegra_car TEGRA124_CLK_EXTERN1>; 1943 1943 clock-names = "pll_a", "pll_a_out0", "mclk"; 1944 1944 }; 1945 + 1946 + thermal-zones { 1947 + cpu { 1948 + trips { 1949 + trip@0 { 1950 + temperature = <101000>; 1951 + hysteresis = <0>; 1952 + type = "critical"; 1953 + }; 1954 + }; 1955 + 1956 + cooling-maps { 1957 + /* There are currently no cooling maps because there are no cooling devices */ 1958 + }; 1959 + }; 1960 + 1961 + mem { 1962 + trips { 1963 + trip@0 { 1964 + temperature = <101000>; 1965 + hysteresis = <0>; 1966 + type = "critical"; 1967 + }; 1968 + }; 1969 + 1970 + cooling-maps { 1971 + /* There are currently no cooling maps because there are no cooling devices */ 1972 + }; 1973 + }; 1974 + 1975 + gpu { 1976 + trips { 1977 + trip@0 { 1978 + temperature = <101000>; 1979 + hysteresis = <0>; 1980 + type = "critical"; 1981 + }; 1982 + }; 1983 + 1984 + cooling-maps { 1985 + /* There are currently no cooling maps because there are no cooling devices */ 1986 + }; 1987 + }; 1988 + }; 1945 1989 };
+47
arch/arm/boot/dts/tegra124.dtsi
··· 4 4 #include <dt-bindings/pinctrl/pinctrl-tegra.h> 5 5 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> 6 6 #include <dt-bindings/interrupt-controller/arm-gic.h> 7 + #include <dt-bindings/thermal/tegra124-soctherm.h> 7 8 8 9 #include "skeleton.dtsi" 9 10 ··· 658 657 status = "disabled"; 659 658 }; 660 659 660 + soctherm: thermal-sensor@0,700e2000 { 661 + compatible = "nvidia,tegra124-soctherm"; 662 + reg = <0x0 0x700e2000 0x0 0x1000>; 663 + interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; 664 + clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, 665 + <&tegra_car TEGRA124_CLK_SOC_THERM>; 666 + clock-names = "tsensor", "soctherm"; 667 + resets = <&tegra_car 78>; 668 + reset-names = "soctherm"; 669 + #thermal-sensor-cells = <1>; 670 + }; 671 + 661 672 ahub@0,70300000 { 662 673 compatible = "nvidia,tegra124-ahub"; 663 674 reg = <0x0 0x70300000 0x0 0x200>, ··· 908 895 device_type = "cpu"; 909 896 compatible = "arm,cortex-a15"; 910 897 reg = <3>; 898 + }; 899 + }; 900 + 901 + thermal-zones { 902 + cpu { 903 + polling-delay-passive = <1000>; 904 + polling-delay = <1000>; 905 + 906 + thermal-sensors = 907 + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; 908 + }; 909 + 910 + mem { 911 + polling-delay-passive = <1000>; 912 + polling-delay = <1000>; 913 + 914 + thermal-sensors = 915 + <&soctherm TEGRA124_SOCTHERM_SENSOR_MEM>; 916 + }; 917 + 918 + gpu { 919 + polling-delay-passive = <1000>; 920 + polling-delay = <1000>; 921 + 922 + thermal-sensors = 923 + <&soctherm TEGRA124_SOCTHERM_SENSOR_GPU>; 924 + }; 925 + 926 + pllx { 927 + polling-delay-passive = <1000>; 928 + polling-delay = <1000>; 929 + 930 + thermal-sensors = 931 + <&soctherm TEGRA124_SOCTHERM_SENSOR_PLLX>; 911 932 }; 912 933 }; 913 934
+6 -3
drivers/hwmon/lm75.c
··· 177 177 }; 178 178 ATTRIBUTE_GROUPS(lm75); 179 179 180 + static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = { 181 + .get_temp = lm75_read_temp, 182 + }; 183 + 180 184 /*-----------------------------------------------------------------------*/ 181 185 182 186 /* device probe and removal */ ··· 300 296 if (IS_ERR(data->hwmon_dev)) 301 297 return PTR_ERR(data->hwmon_dev); 302 298 303 - data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 304 - 0, 299 + data->tz = thermal_zone_of_sensor_register(data->hwmon_dev, 0, 305 300 data->hwmon_dev, 306 - lm75_read_temp, NULL); 301 + &lm75_of_thermal_ops); 307 302 if (IS_ERR(data->tz)) 308 303 data->tz = NULL; 309 304
+5 -1
drivers/hwmon/ntc_thermistor.c
··· 486 486 .attrs = ntc_attributes, 487 487 }; 488 488 489 + static const struct thermal_zone_of_device_ops ntc_of_thermal_ops = { 490 + .get_temp = ntc_read_temp, 491 + }; 492 + 489 493 static int ntc_thermistor_probe(struct platform_device *pdev) 490 494 { 491 495 const struct of_device_id *of_id = ··· 583 579 pdev_id->name); 584 580 585 581 data->tz = thermal_zone_of_sensor_register(data->dev, 0, data->dev, 586 - ntc_read_temp, NULL); 582 + &ntc_of_thermal_ops); 587 583 if (IS_ERR(data->tz)) { 588 584 dev_dbg(&pdev->dev, "Failed to register to thermal fw.\n"); 589 585 data->tz = NULL;
+5 -1
drivers/hwmon/tmp102.c
··· 158 158 #define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) 159 159 #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) 160 160 161 + static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = { 162 + .get_temp = tmp102_read_temp, 163 + }; 164 + 161 165 static int tmp102_probe(struct i2c_client *client, 162 166 const struct i2c_device_id *id) 163 167 { ··· 219 215 } 220 216 tmp102->hwmon_dev = hwmon_dev; 221 217 tmp102->tz = thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, 222 - tmp102_read_temp, NULL); 218 + &tmp102_of_thermal_ops); 223 219 if (IS_ERR(tmp102->tz)) 224 220 tmp102->tz = NULL; 225 221
+32
drivers/thermal/Kconfig
··· 112 112 113 113 If you want this support, you should say Y here. 114 114 115 + config CLOCK_THERMAL 116 + bool "Generic clock cooling support" 117 + depends on COMMON_CLK 118 + depends on PM_OPP 119 + help 120 + This entry implements the generic clock cooling mechanism through 121 + frequency clipping. Typically used to cool off co-processors. The 122 + device that is configured to use this cooling mechanism will be 123 + controlled to reduce clock frequency whenever temperature is high. 124 + 125 + If you want this support, you should say Y here. 126 + 115 127 config THERMAL_EMULATION 116 128 bool "Thermal emulation mode support" 117 129 help ··· 154 142 help 155 143 Enable this to plug the SPEAr thermal sensor driver into the Linux 156 144 thermal framework. 145 + 146 + config ROCKCHIP_THERMAL 147 + tristate "Rockchip thermal driver" 148 + depends on ARCH_ROCKCHIP 149 + depends on RESET_CONTROLLER 150 + help 151 + Rockchip thermal driver provides support for Temperature sensor 152 + ADC (TS-ADC) found on Rockchip SoCs. It supports one critical 153 + trip point. Cpufreq is used as the cooling device and will throttle 154 + CPUs when the Temperature crosses the passive trip point. 157 155 158 156 config RCAR_THERMAL 159 157 tristate "Renesas R-Car thermal driver" ··· 206 184 help 207 185 Enable this option if you want to have support for thermal management 208 186 controller present in Armada 370 and Armada XP SoC. 187 + 188 + config TEGRA_SOCTHERM 189 + tristate "Tegra SOCTHERM thermal management" 190 + depends on ARCH_TEGRA 191 + help 192 + Enable this option for integrated thermal management support on NVIDIA 193 + Tegra124 systems-on-chip. The driver supports four thermal zones 194 + (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal 195 + zones to manage temperatures. This option is also required for the 196 + emergency thermal reset (thermtrip) feature to function. 209 197 210 198 config DB8500_CPUFREQ_COOLING 211 199 tristate "DB8500 cpufreq cooling"
+5
drivers/thermal/Makefile
··· 18 18 # cpufreq cooling 19 19 thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o 20 20 21 + # clock cooling 22 + thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o 23 + 21 24 # platform thermal drivers 22 25 obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o 26 + obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o 23 27 obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o 24 28 obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o 25 29 obj-y += samsung/ ··· 38 34 obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 39 35 obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ 40 36 obj-$(CONFIG_ST_THERMAL) += st/ 37 + obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o
-20
drivers/thermal/armada_thermal.c
··· 35 35 #define PMU_TDC0_OTF_CAL_MASK (0x1 << 30) 36 36 #define PMU_TDC0_START_CAL_MASK (0x1 << 25) 37 37 38 - #define A375_Z1_CAL_RESET_LSB 0x8011e214 39 - #define A375_Z1_CAL_RESET_MSB 0x30a88019 40 - #define A375_Z1_WORKAROUND_BIT BIT(9) 41 - 42 38 #define A375_UNIT_CONTROL_SHIFT 27 43 39 #define A375_UNIT_CONTROL_MASK 0x7 44 40 #define A375_READOUT_INVERT BIT(15) ··· 120 124 struct armada_thermal_priv *priv) 121 125 { 122 126 unsigned long reg; 123 - bool quirk_needed = 124 - !!of_device_is_compatible(pdev->dev.of_node, 125 - "marvell,armada375-z1-thermal"); 126 - 127 - if (quirk_needed) { 128 - /* Ensure these registers have the default (reset) values */ 129 - writel(A375_Z1_CAL_RESET_LSB, priv->control); 130 - writel(A375_Z1_CAL_RESET_MSB, priv->control + 0x4); 131 - } 132 127 133 128 reg = readl(priv->control + 4); 134 129 reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT); 135 130 reg &= ~A375_READOUT_INVERT; 136 131 reg &= ~A375_HW_RESETn; 137 - 138 - if (quirk_needed) 139 - reg |= A375_Z1_WORKAROUND_BIT; 140 132 141 133 writel(reg, priv->control + 4); 142 134 mdelay(20); ··· 241 257 }, 242 258 { 243 259 .compatible = "marvell,armada375-thermal", 244 - .data = &armada375_data, 245 - }, 246 - { 247 - .compatible = "marvell,armada375-z1-thermal", 248 260 .data = &armada375_data, 249 261 }, 250 262 {
+485
drivers/thermal/clock_cooling.c
··· 1 + /* 2 + * drivers/thermal/clock_cooling.c 3 + * 4 + * Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com> 5 + * 6 + * Copyright (C) 2013 Texas Instruments Inc. 7 + * Contact: Eduardo Valentin <eduardo.valentin@ti.com> 8 + * 9 + * Highly based on cpu_cooling.c. 10 + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) 11 + * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> 12 + * 13 + * This program is free software; you can redistribute it and/or modify 14 + * it under the terms of the GNU General Public License as published by 15 + * the Free Software Foundation; version 2 of the License. 16 + * 17 + * This program is distributed in the hope that it will be useful, but 18 + * WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 + * General Public License for more details. 21 + */ 22 + #include <linux/clk.h> 23 + #include <linux/cpufreq.h> 24 + #include <linux/device.h> 25 + #include <linux/err.h> 26 + #include <linux/idr.h> 27 + #include <linux/mutex.h> 28 + #include <linux/pm_opp.h> 29 + #include <linux/slab.h> 30 + #include <linux/thermal.h> 31 + #include <linux/clock_cooling.h> 32 + 33 + /** 34 + * struct clock_cooling_device - data for cooling device with clock 35 + * @id: unique integer value corresponding to each clock_cooling_device 36 + * registered. 37 + * @dev: struct device pointer to the device being used to cool off using 38 + * clock frequencies. 39 + * @cdev: thermal_cooling_device pointer to keep track of the 40 + * registered cooling device. 41 + * @clk_rate_change_nb: reference to notifier block used to receive clock 42 + * rate changes. 43 + * @freq_table: frequency table used to keep track of available frequencies. 44 + * @clock_state: integer value representing the current state of clock 45 + * cooling devices. 46 + * @clock_val: integer value representing the absolute value of the clipped 47 + * frequency. 48 + * @clk: struct clk reference used to enforce clock limits. 49 + * @lock: mutex lock to protect this struct. 50 + * 51 + * This structure is required for keeping information of each 52 + * clock_cooling_device registered. In order to prevent corruption of this a 53 + * mutex @lock is used. 54 + */ 55 + struct clock_cooling_device { 56 + int id; 57 + struct device *dev; 58 + struct thermal_cooling_device *cdev; 59 + struct notifier_block clk_rate_change_nb; 60 + struct cpufreq_frequency_table *freq_table; 61 + unsigned long clock_state; 62 + unsigned long clock_val; 63 + struct clk *clk; 64 + struct mutex lock; /* lock to protect the content of this struct */ 65 + }; 66 + #define to_clock_cooling_device(x) \ 67 + container_of(x, struct clock_cooling_device, clk_rate_change_nb) 68 + static DEFINE_IDR(clock_idr); 69 + static DEFINE_MUTEX(cooling_clock_lock); 70 + 71 + /** 72 + * clock_cooling_get_idr - function to get an unique id. 73 + * @id: int * value generated by this function. 74 + * 75 + * This function will populate @id with an unique 76 + * id, using the idr API. 77 + * 78 + * Return: 0 on success, an error code on failure. 79 + */ 80 + static int clock_cooling_get_idr(int *id) 81 + { 82 + int ret; 83 + 84 + mutex_lock(&cooling_clock_lock); 85 + ret = idr_alloc(&clock_idr, NULL, 0, 0, GFP_KERNEL); 86 + mutex_unlock(&cooling_clock_lock); 87 + if (unlikely(ret < 0)) 88 + return ret; 89 + *id = ret; 90 + 91 + return 0; 92 + } 93 + 94 + /** 95 + * release_idr - function to free the unique id. 96 + * @id: int value representing the unique id. 97 + */ 98 + static void release_idr(int id) 99 + { 100 + mutex_lock(&cooling_clock_lock); 101 + idr_remove(&clock_idr, id); 102 + mutex_unlock(&cooling_clock_lock); 103 + } 104 + 105 + /* Below code defines functions to be used for clock as cooling device */ 106 + 107 + enum clock_cooling_property { 108 + GET_LEVEL, 109 + GET_FREQ, 110 + GET_MAXL, 111 + }; 112 + 113 + /** 114 + * clock_cooling_get_property - fetch a property of interest for a give cpu. 115 + * @ccdev: clock cooling device reference 116 + * @input: query parameter 117 + * @output: query return 118 + * @property: type of query (frequency, level, max level) 119 + * 120 + * This is the common function to 121 + * 1. get maximum clock cooling states 122 + * 2. translate frequency to cooling state 123 + * 3. translate cooling state to frequency 124 + * Note that the code may be not in good shape 125 + * but it is written in this way in order to: 126 + * a) reduce duplicate code as most of the code can be shared. 127 + * b) make sure the logic is consistent when translating between 128 + * cooling states and frequencies. 129 + * 130 + * Return: 0 on success, -EINVAL when invalid parameters are passed. 131 + */ 132 + static int clock_cooling_get_property(struct clock_cooling_device *ccdev, 133 + unsigned long input, 134 + unsigned long *output, 135 + enum clock_cooling_property property) 136 + { 137 + int i; 138 + unsigned long max_level = 0, level = 0; 139 + unsigned int freq = CPUFREQ_ENTRY_INVALID; 140 + int descend = -1; 141 + struct cpufreq_frequency_table *pos, *table = ccdev->freq_table; 142 + 143 + if (!output) 144 + return -EINVAL; 145 + 146 + if (!table) 147 + return -EINVAL; 148 + 149 + cpufreq_for_each_valid_entry(pos, table) { 150 + /* ignore duplicate entry */ 151 + if (freq == pos->frequency) 152 + continue; 153 + 154 + /* get the frequency order */ 155 + if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) 156 + descend = freq > pos->frequency; 157 + 158 + freq = pos->frequency; 159 + max_level++; 160 + } 161 + 162 + /* No valid cpu frequency entry */ 163 + if (max_level == 0) 164 + return -EINVAL; 165 + 166 + /* max_level is an index, not a counter */ 167 + max_level--; 168 + 169 + /* get max level */ 170 + if (property == GET_MAXL) { 171 + *output = max_level; 172 + return 0; 173 + } 174 + 175 + if (property == GET_FREQ) 176 + level = descend ? input : (max_level - input); 177 + 178 + i = 0; 179 + cpufreq_for_each_valid_entry(pos, table) { 180 + /* ignore duplicate entry */ 181 + if (freq == pos->frequency) 182 + continue; 183 + 184 + /* now we have a valid frequency entry */ 185 + freq = pos->frequency; 186 + 187 + if (property == GET_LEVEL && (unsigned int)input == freq) { 188 + /* get level by frequency */ 189 + *output = descend ? i : (max_level - i); 190 + return 0; 191 + } 192 + if (property == GET_FREQ && level == i) { 193 + /* get frequency by level */ 194 + *output = freq; 195 + return 0; 196 + } 197 + i++; 198 + } 199 + 200 + return -EINVAL; 201 + } 202 + 203 + /** 204 + * clock_cooling_get_level - return the cooling level of given clock cooling. 205 + * @cdev: reference of a thermal cooling device of used as clock cooling device 206 + * @freq: the frequency of interest 207 + * 208 + * This function will match the cooling level corresponding to the 209 + * requested @freq and return it. 210 + * 211 + * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID 212 + * otherwise. 213 + */ 214 + unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, 215 + unsigned long freq) 216 + { 217 + struct clock_cooling_device *ccdev = cdev->devdata; 218 + unsigned long val; 219 + 220 + if (clock_cooling_get_property(ccdev, (unsigned long)freq, &val, 221 + GET_LEVEL)) 222 + return THERMAL_CSTATE_INVALID; 223 + 224 + return val; 225 + } 226 + EXPORT_SYMBOL_GPL(clock_cooling_get_level); 227 + 228 + /** 229 + * clock_cooling_get_frequency - get the absolute value of frequency from level. 230 + * @ccdev: clock cooling device reference 231 + * @level: cooling level 232 + * 233 + * This function matches cooling level with frequency. Based on a cooling level 234 + * of frequency, equals cooling state of cpu cooling device, it will return 235 + * the corresponding frequency. 236 + * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc 237 + * 238 + * Return: 0 on error, the corresponding frequency otherwise. 239 + */ 240 + static unsigned long 241 + clock_cooling_get_frequency(struct clock_cooling_device *ccdev, 242 + unsigned long level) 243 + { 244 + int ret = 0; 245 + unsigned long freq; 246 + 247 + ret = clock_cooling_get_property(ccdev, level, &freq, GET_FREQ); 248 + if (ret) 249 + return 0; 250 + 251 + return freq; 252 + } 253 + 254 + /** 255 + * clock_cooling_apply - function to apply frequency clipping. 256 + * @ccdev: clock_cooling_device pointer containing frequency clipping data. 257 + * @cooling_state: value of the cooling state. 258 + * 259 + * Function used to make sure the clock layer is aware of current thermal 260 + * limits. The limits are applied by updating the clock rate in case it is 261 + * higher than the corresponding frequency based on the requested cooling_state. 262 + * 263 + * Return: 0 on success, an error code otherwise (-EINVAL in case wrong 264 + * cooling state). 265 + */ 266 + static int clock_cooling_apply(struct clock_cooling_device *ccdev, 267 + unsigned long cooling_state) 268 + { 269 + unsigned long clip_freq, cur_freq; 270 + int ret = 0; 271 + 272 + /* Here we write the clipping */ 273 + /* Check if the old cooling action is same as new cooling action */ 274 + if (ccdev->clock_state == cooling_state) 275 + return 0; 276 + 277 + clip_freq = clock_cooling_get_frequency(ccdev, cooling_state); 278 + if (!clip_freq) 279 + return -EINVAL; 280 + 281 + cur_freq = clk_get_rate(ccdev->clk); 282 + 283 + mutex_lock(&ccdev->lock); 284 + ccdev->clock_state = cooling_state; 285 + ccdev->clock_val = clip_freq; 286 + /* enforce clock level */ 287 + if (cur_freq > clip_freq) 288 + ret = clk_set_rate(ccdev->clk, clip_freq); 289 + mutex_unlock(&ccdev->lock); 290 + 291 + return ret; 292 + } 293 + 294 + /** 295 + * clock_cooling_clock_notifier - notifier callback on clock rate changes. 296 + * @nb: struct notifier_block * with callback info. 297 + * @event: value showing clock event for which this function invoked. 298 + * @data: callback-specific data 299 + * 300 + * Callback to hijack the notification on clock transition. 301 + * Every time there is a clock change, we intercept all pre change events 302 + * and block the transition in case the new rate infringes thermal limits. 303 + * 304 + * Return: NOTIFY_DONE (success) or NOTIFY_BAD (new_rate > thermal limit). 305 + */ 306 + static int clock_cooling_clock_notifier(struct notifier_block *nb, 307 + unsigned long event, void *data) 308 + { 309 + struct clk_notifier_data *ndata = data; 310 + struct clock_cooling_device *ccdev = to_clock_cooling_device(nb); 311 + 312 + switch (event) { 313 + case PRE_RATE_CHANGE: 314 + /* 315 + * checks on current state 316 + * TODO: current method is not best we can find as it 317 + * allows possibly voltage transitions, in case DVFS 318 + * layer is also hijacking clock pre notifications. 319 + */ 320 + if (ndata->new_rate > ccdev->clock_val) 321 + return NOTIFY_BAD; 322 + /* fall through */ 323 + case POST_RATE_CHANGE: 324 + case ABORT_RATE_CHANGE: 325 + default: 326 + return NOTIFY_DONE; 327 + } 328 + } 329 + 330 + /* clock cooling device thermal callback functions are defined below */ 331 + 332 + /** 333 + * clock_cooling_get_max_state - callback function to get the max cooling state. 334 + * @cdev: thermal cooling device pointer. 335 + * @state: fill this variable with the max cooling state. 336 + * 337 + * Callback for the thermal cooling device to return the clock 338 + * max cooling state. 339 + * 340 + * Return: 0 on success, an error code otherwise. 341 + */ 342 + static int clock_cooling_get_max_state(struct thermal_cooling_device *cdev, 343 + unsigned long *state) 344 + { 345 + struct clock_cooling_device *ccdev = cdev->devdata; 346 + unsigned long count = 0; 347 + int ret; 348 + 349 + ret = clock_cooling_get_property(ccdev, 0, &count, GET_MAXL); 350 + if (!ret) 351 + *state = count; 352 + 353 + return ret; 354 + } 355 + 356 + /** 357 + * clock_cooling_get_cur_state - function to get the current cooling state. 358 + * @cdev: thermal cooling device pointer. 359 + * @state: fill this variable with the current cooling state. 360 + * 361 + * Callback for the thermal cooling device to return the clock 362 + * current cooling state. 363 + * 364 + * Return: 0 (success) 365 + */ 366 + static int clock_cooling_get_cur_state(struct thermal_cooling_device *cdev, 367 + unsigned long *state) 368 + { 369 + struct clock_cooling_device *ccdev = cdev->devdata; 370 + 371 + *state = ccdev->clock_state; 372 + 373 + return 0; 374 + } 375 + 376 + /** 377 + * clock_cooling_set_cur_state - function to set the current cooling state. 378 + * @cdev: thermal cooling device pointer. 379 + * @state: set this variable to the current cooling state. 380 + * 381 + * Callback for the thermal cooling device to change the clock cooling 382 + * current cooling state. 383 + * 384 + * Return: 0 on success, an error code otherwise. 385 + */ 386 + static int clock_cooling_set_cur_state(struct thermal_cooling_device *cdev, 387 + unsigned long state) 388 + { 389 + struct clock_cooling_device *clock_device = cdev->devdata; 390 + 391 + return clock_cooling_apply(clock_device, state); 392 + } 393 + 394 + /* Bind clock callbacks to thermal cooling device ops */ 395 + static struct thermal_cooling_device_ops const clock_cooling_ops = { 396 + .get_max_state = clock_cooling_get_max_state, 397 + .get_cur_state = clock_cooling_get_cur_state, 398 + .set_cur_state = clock_cooling_set_cur_state, 399 + }; 400 + 401 + /** 402 + * clock_cooling_register - function to create clock cooling device. 403 + * @dev: struct device pointer to the device used as clock cooling device. 404 + * @clock_name: string containing the clock used as cooling mechanism. 405 + * 406 + * This interface function registers the clock cooling device with the name 407 + * "thermal-clock-%x". The cooling device is based on clock frequencies. 408 + * The struct device is assumed to be capable of DVFS transitions. 409 + * The OPP layer is used to fetch and fill the available frequencies for 410 + * the referred device. The ordered frequency table is used to control 411 + * the clock cooling device cooling states and to limit clock transitions 412 + * based on the cooling state requested by the thermal framework. 413 + * 414 + * Return: a valid struct thermal_cooling_device pointer on success, 415 + * on failure, it returns a corresponding ERR_PTR(). 416 + */ 417 + struct thermal_cooling_device * 418 + clock_cooling_register(struct device *dev, const char *clock_name) 419 + { 420 + struct thermal_cooling_device *cdev; 421 + struct clock_cooling_device *ccdev = NULL; 422 + char dev_name[THERMAL_NAME_LENGTH]; 423 + int ret = 0; 424 + 425 + ccdev = devm_kzalloc(dev, sizeof(*ccdev), GFP_KERNEL); 426 + if (!ccdev) 427 + return ERR_PTR(-ENOMEM); 428 + 429 + ccdev->dev = dev; 430 + ccdev->clk = devm_clk_get(dev, clock_name); 431 + if (IS_ERR(ccdev->clk)) 432 + return ERR_CAST(ccdev->clk); 433 + 434 + ret = clock_cooling_get_idr(&ccdev->id); 435 + if (ret) 436 + return ERR_PTR(-EINVAL); 437 + 438 + snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id); 439 + 440 + cdev = thermal_cooling_device_register(dev_name, ccdev, 441 + &clock_cooling_ops); 442 + if (IS_ERR(cdev)) { 443 + release_idr(ccdev->id); 444 + return ERR_PTR(-EINVAL); 445 + } 446 + ccdev->cdev = cdev; 447 + ccdev->clk_rate_change_nb.notifier_call = clock_cooling_clock_notifier; 448 + 449 + /* Assuming someone has already filled the opp table for this device */ 450 + ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table); 451 + if (ret) { 452 + release_idr(ccdev->id); 453 + return ERR_PTR(ret); 454 + } 455 + ccdev->clock_state = 0; 456 + ccdev->clock_val = clock_cooling_get_frequency(ccdev, 0); 457 + 458 + clk_notifier_register(ccdev->clk, &ccdev->clk_rate_change_nb); 459 + 460 + return cdev; 461 + } 462 + EXPORT_SYMBOL_GPL(clock_cooling_register); 463 + 464 + /** 465 + * clock_cooling_unregister - function to remove clock cooling device. 466 + * @cdev: thermal cooling device pointer. 467 + * 468 + * This interface function unregisters the "thermal-clock-%x" cooling device. 469 + */ 470 + void clock_cooling_unregister(struct thermal_cooling_device *cdev) 471 + { 472 + struct clock_cooling_device *ccdev; 473 + 474 + if (!cdev) 475 + return; 476 + 477 + ccdev = cdev->devdata; 478 + 479 + clk_notifier_unregister(ccdev->clk, &ccdev->clk_rate_change_nb); 480 + dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table); 481 + 482 + thermal_cooling_device_unregister(ccdev->cdev); 483 + release_idr(ccdev->id); 484 + } 485 + EXPORT_SYMBOL_GPL(clock_cooling_unregister);
+7 -5
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
··· 131 131 pr_warn("Failed to get target ACPI device\n"); 132 132 } 133 133 134 + result = 0; 135 + 134 136 *trtp = trts; 135 137 /* don't count bad entries */ 136 138 *trt_count -= nr_bad_entries; ··· 319 317 { 320 318 int ret = 0; 321 319 unsigned long length = 0; 322 - unsigned long count = 0; 320 + int count = 0; 323 321 char __user *arg = (void __user *)__arg; 324 322 struct trt *trts; 325 323 struct art *arts; 326 324 327 325 switch (cmd) { 328 326 case ACPI_THERMAL_GET_TRT_COUNT: 329 - ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count, 327 + ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, 330 328 &trts, false); 331 329 kfree(trts); 332 330 if (!ret) 333 331 return put_user(count, (unsigned long __user *)__arg); 334 332 return ret; 335 333 case ACPI_THERMAL_GET_TRT_LEN: 336 - ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count, 334 + ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, 337 335 &trts, false); 338 336 kfree(trts); 339 337 length = count * sizeof(union trt_object); ··· 343 341 case ACPI_THERMAL_GET_TRT: 344 342 return fill_trt(arg); 345 343 case ACPI_THERMAL_GET_ART_COUNT: 346 - ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count, 344 + ret = acpi_parse_art(acpi_thermal_rel_handle, &count, 347 345 &arts, false); 348 346 kfree(arts); 349 347 if (!ret) 350 348 return put_user(count, (unsigned long __user *)__arg); 351 349 return ret; 352 350 case ACPI_THERMAL_GET_ART_LEN: 353 - ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count, 351 + ret = acpi_parse_art(acpi_thermal_rel_handle, &count, 354 352 &arts, false); 355 353 kfree(arts); 356 354 length = count * sizeof(union art_object);
+78 -2
drivers/thermal/int340x_thermal/int3400_thermal.c
··· 43 43 struct trt *trts; 44 44 u8 uuid_bitmap; 45 45 int rel_misc_dev_res; 46 + int current_uuid_index; 47 + }; 48 + 49 + static ssize_t available_uuids_show(struct device *dev, 50 + struct device_attribute *attr, 51 + char *buf) 52 + { 53 + struct platform_device *pdev = to_platform_device(dev); 54 + struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 55 + int i; 56 + int length = 0; 57 + 58 + for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { 59 + if (priv->uuid_bitmap & (1 << i)) 60 + if (PAGE_SIZE - length > 0) 61 + length += snprintf(&buf[length], 62 + PAGE_SIZE - length, 63 + "%s\n", 64 + int3400_thermal_uuids[i]); 65 + } 66 + 67 + return length; 68 + } 69 + 70 + static ssize_t current_uuid_show(struct device *dev, 71 + struct device_attribute *devattr, char *buf) 72 + { 73 + struct platform_device *pdev = to_platform_device(dev); 74 + struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 75 + 76 + if (priv->uuid_bitmap & (1 << priv->current_uuid_index)) 77 + return sprintf(buf, "%s\n", 78 + int3400_thermal_uuids[priv->current_uuid_index]); 79 + else 80 + return sprintf(buf, "INVALID\n"); 81 + } 82 + 83 + static ssize_t current_uuid_store(struct device *dev, 84 + struct device_attribute *attr, 85 + const char *buf, size_t count) 86 + { 87 + struct platform_device *pdev = to_platform_device(dev); 88 + struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 89 + int i; 90 + 91 + for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) { 92 + if ((priv->uuid_bitmap & (1 << i)) && 93 + !(strncmp(buf, int3400_thermal_uuids[i], 94 + sizeof(int3400_thermal_uuids[i]) - 1))) { 95 + priv->current_uuid_index = i; 96 + return count; 97 + } 98 + } 99 + 100 + return -EINVAL; 101 + } 102 + 103 + static DEVICE_ATTR(current_uuid, 0644, current_uuid_show, current_uuid_store); 104 + static DEVICE_ATTR_RO(available_uuids); 105 + static struct attribute *uuid_attrs[] = { 106 + &dev_attr_available_uuids.attr, 107 + &dev_attr_current_uuid.attr, 108 + NULL 109 + }; 110 + 111 + static struct attribute_group uuid_attribute_group = { 112 + .attrs = uuid_attrs, 113 + .name = "uuids" 46 114 }; 47 115 48 116 static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) ··· 228 160 229 161 if (enable != priv->mode) { 230 162 priv->mode = enable; 231 - /* currently, only PASSIVE COOLING is supported */ 232 163 result = int3400_thermal_run_osc(priv->adev->handle, 233 - INT3400_THERMAL_PASSIVE_1, enable); 164 + priv->current_uuid_index, 165 + enable); 234 166 } 235 167 return result; 236 168 } ··· 291 223 priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add( 292 224 priv->adev->handle); 293 225 226 + result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group); 227 + if (result) 228 + goto free_zone; 229 + 294 230 return 0; 231 + 232 + free_zone: 233 + thermal_zone_device_unregister(priv->thermal); 295 234 free_trt: 296 235 kfree(priv->trts); 297 236 free_art: ··· 315 240 if (!priv->rel_misc_dev_res) 316 241 acpi_thermal_rel_misc_device_remove(priv->adev->handle); 317 242 243 + sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 318 244 thermal_zone_device_unregister(priv->thermal); 319 245 kfree(priv->trts); 320 246 kfree(priv->arts);
+1 -3
drivers/thermal/int340x_thermal/int3403_thermal.c
··· 293 293 return 0; 294 294 295 295 err_free_obj: 296 - if (obj->tzone) 297 - thermal_zone_device_unregister(obj->tzone); 296 + thermal_zone_device_unregister(obj->tzone); 298 297 return result; 299 298 } 300 299 ··· 470 471 .remove = int3403_remove, 471 472 .driver = { 472 473 .name = "int3403 thermal", 473 - .owner = THIS_MODULE, 474 474 .acpi_match_table = int3403_device_ids, 475 475 }, 476 476 };
+1
drivers/thermal/intel_powerclamp.c
··· 689 689 { X86_VENDOR_INTEL, 6, 0x3f}, 690 690 { X86_VENDOR_INTEL, 6, 0x45}, 691 691 { X86_VENDOR_INTEL, 6, 0x46}, 692 + { X86_VENDOR_INTEL, 6, 0x4c}, 692 693 {} 693 694 }; 694 695 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
+7 -5
drivers/thermal/intel_soc_dts_thermal.c
··· 360 360 u32 sticky_out; 361 361 int status; 362 362 u32 ptmc_out; 363 + unsigned long flags; 364 + 365 + spin_lock_irqsave(&intr_notify_lock, flags); 363 366 364 367 /* Clear APIC interrupt */ 365 368 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, ··· 381 378 /* reset sticky bit */ 382 379 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 383 380 SOC_DTS_OFFSET_PTTSS, sticky_out); 381 + spin_unlock_irqrestore(&intr_notify_lock, flags); 382 + 384 383 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 385 384 pr_debug("TZD update for zone %d\n", i); 386 385 thermal_zone_device_update(soc_dts[i]->tzone); 387 386 } 388 - } 387 + } else 388 + spin_unlock_irqrestore(&intr_notify_lock, flags); 389 389 390 390 } 391 391 392 392 static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) 393 393 { 394 - unsigned long flags; 395 - 396 - spin_lock_irqsave(&intr_notify_lock, flags); 397 394 proc_thermal_interrupt(); 398 - spin_unlock_irqrestore(&intr_notify_lock, flags); 399 395 pr_debug("proc_thermal_interrupt\n"); 400 396 401 397 return IRQ_HANDLED;
+108 -40
drivers/thermal/of-thermal.c
··· 30 30 #include <linux/err.h> 31 31 #include <linux/export.h> 32 32 #include <linux/string.h> 33 + #include <linux/thermal.h> 33 34 34 35 #include "thermal_core.h" 35 36 36 37 /*** Private data structures to represent thermal device tree data ***/ 37 - 38 - /** 39 - * struct __thermal_trip - representation of a point in temperature domain 40 - * @np: pointer to struct device_node that this trip point was created from 41 - * @temperature: temperature value in miliCelsius 42 - * @hysteresis: relative hysteresis in miliCelsius 43 - * @type: trip point type 44 - */ 45 - 46 - struct __thermal_trip { 47 - struct device_node *np; 48 - unsigned long int temperature; 49 - unsigned long int hysteresis; 50 - enum thermal_trip_type type; 51 - }; 52 38 53 39 /** 54 40 * struct __thermal_bind_param - a match between trip and cooling device ··· 63 77 * @num_tbps: number of thermal bind params 64 78 * @tbps: an array of thermal bind params (0..num_tbps - 1) 65 79 * @sensor_data: sensor private data used while reading temperature and trend 66 - * @get_temp: sensor callback to read temperature 67 - * @get_trend: sensor callback to read temperature trend 80 + * @ops: set of callbacks to handle the thermal zone based on DT 68 81 */ 69 82 70 83 struct __thermal_zone { ··· 73 88 74 89 /* trip data */ 75 90 int ntrips; 76 - struct __thermal_trip *trips; 91 + struct thermal_trip *trips; 77 92 78 93 /* cooling binding data */ 79 94 int num_tbps; ··· 81 96 82 97 /* sensor interface */ 83 98 void *sensor_data; 84 - int (*get_temp)(void *, long *); 85 - int (*get_trend)(void *, long *); 99 + const struct thermal_zone_of_device_ops *ops; 86 100 }; 87 101 88 102 /*** DT thermal zone device callbacks ***/ ··· 91 107 { 92 108 struct __thermal_zone *data = tz->devdata; 93 109 94 - if (!data->get_temp) 110 + if (!data->ops->get_temp) 95 111 return -EINVAL; 96 112 97 - return data->get_temp(data->sensor_data, temp); 113 + return data->ops->get_temp(data->sensor_data, temp); 114 + } 115 + 116 + /** 117 + * of_thermal_get_ntrips - function to export number of available trip 118 + * points. 119 + * @tz: pointer to a thermal zone 120 + * 121 + * This function is a globally visible wrapper to get number of trip points 122 + * stored in the local struct __thermal_zone 123 + * 124 + * Return: number of available trip points, -ENODEV when data not available 125 + */ 126 + int of_thermal_get_ntrips(struct thermal_zone_device *tz) 127 + { 128 + struct __thermal_zone *data = tz->devdata; 129 + 130 + if (!data || IS_ERR(data)) 131 + return -ENODEV; 132 + 133 + return data->ntrips; 134 + } 135 + EXPORT_SYMBOL_GPL(of_thermal_get_ntrips); 136 + 137 + /** 138 + * of_thermal_is_trip_valid - function to check if trip point is valid 139 + * 140 + * @tz: pointer to a thermal zone 141 + * @trip: trip point to evaluate 142 + * 143 + * This function is responsible for checking if passed trip point is valid 144 + * 145 + * Return: true if trip point is valid, false otherwise 146 + */ 147 + bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip) 148 + { 149 + struct __thermal_zone *data = tz->devdata; 150 + 151 + if (!data || trip >= data->ntrips || trip < 0) 152 + return false; 153 + 154 + return true; 155 + } 156 + EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid); 157 + 158 + /** 159 + * of_thermal_get_trip_points - function to get access to a globally exported 160 + * trip points 161 + * 162 + * @tz: pointer to a thermal zone 163 + * 164 + * This function provides a pointer to trip points table 165 + * 166 + * Return: pointer to trip points table, NULL otherwise 167 + */ 168 + const struct thermal_trip * const 169 + of_thermal_get_trip_points(struct thermal_zone_device *tz) 170 + { 171 + struct __thermal_zone *data = tz->devdata; 172 + 173 + if (!data) 174 + return NULL; 175 + 176 + return data->trips; 177 + } 178 + EXPORT_SYMBOL_GPL(of_thermal_get_trip_points); 179 + 180 + /** 181 + * of_thermal_set_emul_temp - function to set emulated temperature 182 + * 183 + * @tz: pointer to a thermal zone 184 + * @temp: temperature to set 185 + * 186 + * This function gives the ability to set emulated value of temperature, 187 + * which is handy for debugging 188 + * 189 + * Return: zero on success, error code otherwise 190 + */ 191 + static int of_thermal_set_emul_temp(struct thermal_zone_device *tz, 192 + unsigned long temp) 193 + { 194 + struct __thermal_zone *data = tz->devdata; 195 + 196 + if (!data->ops || !data->ops->set_emul_temp) 197 + return -EINVAL; 198 + 199 + return data->ops->set_emul_temp(data->sensor_data, temp); 98 200 } 99 201 100 202 static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip, ··· 190 120 long dev_trend; 191 121 int r; 192 122 193 - if (!data->get_trend) 123 + if (!data->ops->get_trend) 194 124 return -EINVAL; 195 125 196 - r = data->get_trend(data->sensor_data, &dev_trend); 126 + r = data->ops->get_trend(data->sensor_data, &dev_trend); 197 127 if (r) 198 128 return r; 199 129 ··· 394 324 static struct thermal_zone_device * 395 325 thermal_zone_of_add_sensor(struct device_node *zone, 396 326 struct device_node *sensor, void *data, 397 - int (*get_temp)(void *, long *), 398 - int (*get_trend)(void *, long *)) 327 + const struct thermal_zone_of_device_ops *ops) 399 328 { 400 329 struct thermal_zone_device *tzd; 401 330 struct __thermal_zone *tz; ··· 405 336 406 337 tz = tzd->devdata; 407 338 339 + if (!ops) 340 + return ERR_PTR(-EINVAL); 341 + 408 342 mutex_lock(&tzd->lock); 409 - tz->get_temp = get_temp; 410 - tz->get_trend = get_trend; 343 + tz->ops = ops; 411 344 tz->sensor_data = data; 412 345 413 346 tzd->ops->get_temp = of_thermal_get_temp; 414 347 tzd->ops->get_trend = of_thermal_get_trend; 348 + tzd->ops->set_emul_temp = of_thermal_set_emul_temp; 415 349 mutex_unlock(&tzd->lock); 416 350 417 351 return tzd; ··· 428 356 * than one sensors 429 357 * @data: a private pointer (owned by the caller) that will be passed 430 358 * back, when a temperature reading is needed. 431 - * @get_temp: a pointer to a function that reads the sensor temperature. 432 - * @get_trend: a pointer to a function that reads the sensor temperature trend. 359 + * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. 433 360 * 434 361 * This function will search the list of thermal zones described in device 435 362 * tree and look for the zone that refer to the sensor device pointed by ··· 453 382 * check the return value with help of IS_ERR() helper. 454 383 */ 455 384 struct thermal_zone_device * 456 - thermal_zone_of_sensor_register(struct device *dev, int sensor_id, 457 - void *data, int (*get_temp)(void *, long *), 458 - int (*get_trend)(void *, long *)) 385 + thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, 386 + const struct thermal_zone_of_device_ops *ops) 459 387 { 460 388 struct device_node *np, *child, *sensor_np; 461 389 struct thermal_zone_device *tzd = ERR_PTR(-ENODEV); ··· 496 426 497 427 if (sensor_specs.np == sensor_np && id == sensor_id) { 498 428 tzd = thermal_zone_of_add_sensor(child, sensor_np, 499 - data, 500 - get_temp, 501 - get_trend); 429 + data, ops); 502 430 of_node_put(sensor_specs.np); 503 431 of_node_put(child); 504 432 goto exit; ··· 543 475 mutex_lock(&tzd->lock); 544 476 tzd->ops->get_temp = NULL; 545 477 tzd->ops->get_trend = NULL; 478 + tzd->ops->set_emul_temp = NULL; 546 479 547 - tz->get_temp = NULL; 548 - tz->get_trend = NULL; 480 + tz->ops = NULL; 549 481 tz->sensor_data = NULL; 550 482 mutex_unlock(&tzd->lock); 551 483 } ··· 569 501 */ 570 502 static int thermal_of_populate_bind_params(struct device_node *np, 571 503 struct __thermal_bind_params *__tbp, 572 - struct __thermal_trip *trips, 504 + struct thermal_trip *trips, 573 505 int ntrips) 574 506 { 575 507 struct of_phandle_args cooling_spec; ··· 672 604 * Return: 0 on success, proper error code otherwise 673 605 */ 674 606 static int thermal_of_populate_trip(struct device_node *np, 675 - struct __thermal_trip *trip) 607 + struct thermal_trip *trip) 676 608 { 677 609 int prop; 678 610 int ret;
+693
drivers/thermal/rockchip_thermal.c
··· 1 + /* 2 + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + */ 13 + 14 + #include <linux/clk.h> 15 + #include <linux/delay.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/io.h> 18 + #include <linux/module.h> 19 + #include <linux/of.h> 20 + #include <linux/of_address.h> 21 + #include <linux/of_irq.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/reset.h> 24 + #include <linux/thermal.h> 25 + 26 + /** 27 + * If the temperature over a period of time High, 28 + * the resulting TSHUT gave CRU module,let it reset the entire chip, 29 + * or via GPIO give PMIC. 30 + */ 31 + enum tshut_mode { 32 + TSHUT_MODE_CRU = 0, 33 + TSHUT_MODE_GPIO, 34 + }; 35 + 36 + /** 37 + * the system Temperature Sensors tshut(tshut) polarity 38 + * the bit 8 is tshut polarity. 39 + * 0: low active, 1: high active 40 + */ 41 + enum tshut_polarity { 42 + TSHUT_LOW_ACTIVE = 0, 43 + TSHUT_HIGH_ACTIVE, 44 + }; 45 + 46 + /** 47 + * The system has three Temperature Sensors. channel 0 is reserved, 48 + * channel 1 is for CPU, and channel 2 is for GPU. 49 + */ 50 + enum sensor_id { 51 + SENSOR_CPU = 1, 52 + SENSOR_GPU, 53 + }; 54 + 55 + struct rockchip_tsadc_chip { 56 + /* The hardware-controlled tshut property */ 57 + long tshut_temp; 58 + enum tshut_mode tshut_mode; 59 + enum tshut_polarity tshut_polarity; 60 + 61 + /* Chip-wide methods */ 62 + void (*initialize)(void __iomem *reg, enum tshut_polarity p); 63 + void (*irq_ack)(void __iomem *reg); 64 + void (*control)(void __iomem *reg, bool on); 65 + 66 + /* Per-sensor methods */ 67 + int (*get_temp)(int chn, void __iomem *reg, long *temp); 68 + void (*set_tshut_temp)(int chn, void __iomem *reg, long temp); 69 + void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); 70 + }; 71 + 72 + struct rockchip_thermal_sensor { 73 + struct rockchip_thermal_data *thermal; 74 + struct thermal_zone_device *tzd; 75 + enum sensor_id id; 76 + }; 77 + 78 + #define NUM_SENSORS 2 /* Ignore unused sensor 0 */ 79 + 80 + struct rockchip_thermal_data { 81 + const struct rockchip_tsadc_chip *chip; 82 + struct platform_device *pdev; 83 + struct reset_control *reset; 84 + 85 + struct rockchip_thermal_sensor sensors[NUM_SENSORS]; 86 + 87 + struct clk *clk; 88 + struct clk *pclk; 89 + 90 + void __iomem *regs; 91 + 92 + long tshut_temp; 93 + enum tshut_mode tshut_mode; 94 + enum tshut_polarity tshut_polarity; 95 + }; 96 + 97 + /* TSADC V2 Sensor info define: */ 98 + #define TSADCV2_AUTO_CON 0x04 99 + #define TSADCV2_INT_EN 0x08 100 + #define TSADCV2_INT_PD 0x0c 101 + #define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) 102 + #define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) 103 + #define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 104 + #define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 105 + #define TSADCV2_AUTO_PERIOD 0x68 106 + #define TSADCV2_AUTO_PERIOD_HT 0x6c 107 + 108 + #define TSADCV2_AUTO_EN BIT(0) 109 + #define TSADCV2_AUTO_DISABLE ~BIT(0) 110 + #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) 111 + #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) 112 + #define TSADCV2_AUTO_TSHUT_POLARITY_LOW ~BIT(8) 113 + 114 + #define TSADCV2_INT_SRC_EN(chn) BIT(chn) 115 + #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) 116 + #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) 117 + 118 + #define TSADCV2_INT_PD_CLEAR ~BIT(8) 119 + 120 + #define TSADCV2_DATA_MASK 0xfff 121 + #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 122 + #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 123 + #define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ 124 + #define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ 125 + 126 + struct tsadc_table { 127 + unsigned long code; 128 + long temp; 129 + }; 130 + 131 + static const struct tsadc_table v2_code_table[] = { 132 + {TSADCV2_DATA_MASK, -40000}, 133 + {3800, -40000}, 134 + {3792, -35000}, 135 + {3783, -30000}, 136 + {3774, -25000}, 137 + {3765, -20000}, 138 + {3756, -15000}, 139 + {3747, -10000}, 140 + {3737, -5000}, 141 + {3728, 0}, 142 + {3718, 5000}, 143 + {3708, 10000}, 144 + {3698, 15000}, 145 + {3688, 20000}, 146 + {3678, 25000}, 147 + {3667, 30000}, 148 + {3656, 35000}, 149 + {3645, 40000}, 150 + {3634, 45000}, 151 + {3623, 50000}, 152 + {3611, 55000}, 153 + {3600, 60000}, 154 + {3588, 65000}, 155 + {3575, 70000}, 156 + {3563, 75000}, 157 + {3550, 80000}, 158 + {3537, 85000}, 159 + {3524, 90000}, 160 + {3510, 95000}, 161 + {3496, 100000}, 162 + {3482, 105000}, 163 + {3467, 110000}, 164 + {3452, 115000}, 165 + {3437, 120000}, 166 + {3421, 125000}, 167 + {0, 125000}, 168 + }; 169 + 170 + static u32 rk_tsadcv2_temp_to_code(long temp) 171 + { 172 + int high, low, mid; 173 + 174 + low = 0; 175 + high = ARRAY_SIZE(v2_code_table) - 1; 176 + mid = (high + low) / 2; 177 + 178 + if (temp < v2_code_table[low].temp || temp > v2_code_table[high].temp) 179 + return 0; 180 + 181 + while (low <= high) { 182 + if (temp == v2_code_table[mid].temp) 183 + return v2_code_table[mid].code; 184 + else if (temp < v2_code_table[mid].temp) 185 + high = mid - 1; 186 + else 187 + low = mid + 1; 188 + mid = (low + high) / 2; 189 + } 190 + 191 + return 0; 192 + } 193 + 194 + static long rk_tsadcv2_code_to_temp(u32 code) 195 + { 196 + int high, low, mid; 197 + 198 + low = 0; 199 + high = ARRAY_SIZE(v2_code_table) - 1; 200 + mid = (high + low) / 2; 201 + 202 + if (code > v2_code_table[low].code || code < v2_code_table[high].code) 203 + return 125000; /* No code available, return max temperature */ 204 + 205 + while (low <= high) { 206 + if (code >= v2_code_table[mid].code && code < 207 + v2_code_table[mid - 1].code) 208 + return v2_code_table[mid].temp; 209 + else if (code < v2_code_table[mid].code) 210 + low = mid + 1; 211 + else 212 + high = mid - 1; 213 + mid = (low + high) / 2; 214 + } 215 + 216 + return 125000; 217 + } 218 + 219 + /** 220 + * rk_tsadcv2_initialize - initialize TASDC Controller 221 + * (1) Set TSADCV2_AUTO_PERIOD, configure the interleave between 222 + * every two accessing of TSADC in normal operation. 223 + * (2) Set TSADCV2_AUTO_PERIOD_HT, configure the interleave between 224 + * every two accessing of TSADC after the temperature is higher 225 + * than COM_SHUT or COM_INT. 226 + * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE, 227 + * if the temperature is higher than COMP_INT or COMP_SHUT for 228 + * "debounce" times, TSADC controller will generate interrupt or TSHUT. 229 + */ 230 + static void rk_tsadcv2_initialize(void __iomem *regs, 231 + enum tshut_polarity tshut_polarity) 232 + { 233 + if (tshut_polarity == TSHUT_HIGH_ACTIVE) 234 + writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_HIGH), 235 + regs + TSADCV2_AUTO_CON); 236 + else 237 + writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_LOW), 238 + regs + TSADCV2_AUTO_CON); 239 + 240 + writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); 241 + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, 242 + regs + TSADCV2_HIGHT_INT_DEBOUNCE); 243 + writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, 244 + regs + TSADCV2_AUTO_PERIOD_HT); 245 + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, 246 + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); 247 + } 248 + 249 + static void rk_tsadcv2_irq_ack(void __iomem *regs) 250 + { 251 + u32 val; 252 + 253 + val = readl_relaxed(regs + TSADCV2_INT_PD); 254 + writel_relaxed(val & TSADCV2_INT_PD_CLEAR, regs + TSADCV2_INT_PD); 255 + } 256 + 257 + static void rk_tsadcv2_control(void __iomem *regs, bool enable) 258 + { 259 + u32 val; 260 + 261 + val = readl_relaxed(regs + TSADCV2_AUTO_CON); 262 + if (enable) 263 + val |= TSADCV2_AUTO_EN; 264 + else 265 + val &= ~TSADCV2_AUTO_EN; 266 + 267 + writel_relaxed(val, regs + TSADCV2_AUTO_CON); 268 + } 269 + 270 + static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, long *temp) 271 + { 272 + u32 val; 273 + 274 + /* the A/D value of the channel last conversion need some time */ 275 + val = readl_relaxed(regs + TSADCV2_DATA(chn)); 276 + if (val == 0) 277 + return -EAGAIN; 278 + 279 + *temp = rk_tsadcv2_code_to_temp(val); 280 + 281 + return 0; 282 + } 283 + 284 + static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp) 285 + { 286 + u32 tshut_value, val; 287 + 288 + tshut_value = rk_tsadcv2_temp_to_code(temp); 289 + writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); 290 + 291 + /* TSHUT will be valid */ 292 + val = readl_relaxed(regs + TSADCV2_AUTO_CON); 293 + writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON); 294 + } 295 + 296 + static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, 297 + enum tshut_mode mode) 298 + { 299 + u32 val; 300 + 301 + val = readl_relaxed(regs + TSADCV2_INT_EN); 302 + if (mode == TSHUT_MODE_GPIO) { 303 + val &= ~TSADCV2_SHUT_2CRU_SRC_EN(chn); 304 + val |= TSADCV2_SHUT_2GPIO_SRC_EN(chn); 305 + } else { 306 + val &= ~TSADCV2_SHUT_2GPIO_SRC_EN(chn); 307 + val |= TSADCV2_SHUT_2CRU_SRC_EN(chn); 308 + } 309 + 310 + writel_relaxed(val, regs + TSADCV2_INT_EN); 311 + } 312 + 313 + static const struct rockchip_tsadc_chip rk3288_tsadc_data = { 314 + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ 315 + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ 316 + .tshut_temp = 95000, 317 + 318 + .initialize = rk_tsadcv2_initialize, 319 + .irq_ack = rk_tsadcv2_irq_ack, 320 + .control = rk_tsadcv2_control, 321 + .get_temp = rk_tsadcv2_get_temp, 322 + .set_tshut_temp = rk_tsadcv2_tshut_temp, 323 + .set_tshut_mode = rk_tsadcv2_tshut_mode, 324 + }; 325 + 326 + static const struct of_device_id of_rockchip_thermal_match[] = { 327 + { 328 + .compatible = "rockchip,rk3288-tsadc", 329 + .data = (void *)&rk3288_tsadc_data, 330 + }, 331 + { /* end */ }, 332 + }; 333 + MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match); 334 + 335 + static void 336 + rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on) 337 + { 338 + struct thermal_zone_device *tzd = sensor->tzd; 339 + 340 + tzd->ops->set_mode(tzd, 341 + on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED); 342 + } 343 + 344 + static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) 345 + { 346 + struct rockchip_thermal_data *thermal = dev; 347 + int i; 348 + 349 + dev_dbg(&thermal->pdev->dev, "thermal alarm\n"); 350 + 351 + thermal->chip->irq_ack(thermal->regs); 352 + 353 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) 354 + thermal_zone_device_update(thermal->sensors[i].tzd); 355 + 356 + return IRQ_HANDLED; 357 + } 358 + 359 + static int rockchip_thermal_get_temp(void *_sensor, long *out_temp) 360 + { 361 + struct rockchip_thermal_sensor *sensor = _sensor; 362 + struct rockchip_thermal_data *thermal = sensor->thermal; 363 + const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip; 364 + int retval; 365 + 366 + retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp); 367 + dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %ld, retval: %d\n", 368 + sensor->id, *out_temp, retval); 369 + 370 + return retval; 371 + } 372 + 373 + static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = { 374 + .get_temp = rockchip_thermal_get_temp, 375 + }; 376 + 377 + static int rockchip_configure_from_dt(struct device *dev, 378 + struct device_node *np, 379 + struct rockchip_thermal_data *thermal) 380 + { 381 + u32 shut_temp, tshut_mode, tshut_polarity; 382 + 383 + if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) { 384 + dev_warn(dev, 385 + "Missing tshut temp property, using default %ld\n", 386 + thermal->chip->tshut_temp); 387 + thermal->tshut_temp = thermal->chip->tshut_temp; 388 + } else { 389 + thermal->tshut_temp = shut_temp; 390 + } 391 + 392 + if (thermal->tshut_temp > INT_MAX) { 393 + dev_err(dev, "Invalid tshut temperature specified: %ld\n", 394 + thermal->tshut_temp); 395 + return -ERANGE; 396 + } 397 + 398 + if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) { 399 + dev_warn(dev, 400 + "Missing tshut mode property, using default (%s)\n", 401 + thermal->chip->tshut_mode == TSHUT_MODE_GPIO ? 402 + "gpio" : "cru"); 403 + thermal->tshut_mode = thermal->chip->tshut_mode; 404 + } else { 405 + thermal->tshut_mode = tshut_mode; 406 + } 407 + 408 + if (thermal->tshut_mode > 1) { 409 + dev_err(dev, "Invalid tshut mode specified: %d\n", 410 + thermal->tshut_mode); 411 + return -EINVAL; 412 + } 413 + 414 + if (of_property_read_u32(np, "rockchip,hw-tshut-polarity", 415 + &tshut_polarity)) { 416 + dev_warn(dev, 417 + "Missing tshut-polarity property, using default (%s)\n", 418 + thermal->chip->tshut_polarity == TSHUT_LOW_ACTIVE ? 419 + "low" : "high"); 420 + thermal->tshut_polarity = thermal->chip->tshut_polarity; 421 + } else { 422 + thermal->tshut_polarity = tshut_polarity; 423 + } 424 + 425 + if (thermal->tshut_polarity > 1) { 426 + dev_err(dev, "Invalid tshut-polarity specified: %d\n", 427 + thermal->tshut_polarity); 428 + return -EINVAL; 429 + } 430 + 431 + return 0; 432 + } 433 + 434 + static int 435 + rockchip_thermal_register_sensor(struct platform_device *pdev, 436 + struct rockchip_thermal_data *thermal, 437 + struct rockchip_thermal_sensor *sensor, 438 + enum sensor_id id) 439 + { 440 + const struct rockchip_tsadc_chip *tsadc = thermal->chip; 441 + int error; 442 + 443 + tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); 444 + tsadc->set_tshut_temp(id, thermal->regs, thermal->tshut_temp); 445 + 446 + sensor->thermal = thermal; 447 + sensor->id = id; 448 + sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor, 449 + &rockchip_of_thermal_ops); 450 + if (IS_ERR(sensor->tzd)) { 451 + error = PTR_ERR(sensor->tzd); 452 + dev_err(&pdev->dev, "failed to register sensor %d: %d\n", 453 + id, error); 454 + return error; 455 + } 456 + 457 + return 0; 458 + } 459 + 460 + /* 461 + * Reset TSADC Controller, reset all tsadc registers. 462 + */ 463 + static void rockchip_thermal_reset_controller(struct reset_control *reset) 464 + { 465 + reset_control_assert(reset); 466 + usleep_range(10, 20); 467 + reset_control_deassert(reset); 468 + } 469 + 470 + static int rockchip_thermal_probe(struct platform_device *pdev) 471 + { 472 + struct device_node *np = pdev->dev.of_node; 473 + struct rockchip_thermal_data *thermal; 474 + const struct of_device_id *match; 475 + struct resource *res; 476 + int irq; 477 + int i; 478 + int error; 479 + 480 + match = of_match_node(of_rockchip_thermal_match, np); 481 + if (!match) 482 + return -ENXIO; 483 + 484 + irq = platform_get_irq(pdev, 0); 485 + if (irq < 0) { 486 + dev_err(&pdev->dev, "no irq resource?\n"); 487 + return -EINVAL; 488 + } 489 + 490 + thermal = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_thermal_data), 491 + GFP_KERNEL); 492 + if (!thermal) 493 + return -ENOMEM; 494 + 495 + thermal->pdev = pdev; 496 + 497 + thermal->chip = (const struct rockchip_tsadc_chip *)match->data; 498 + if (!thermal->chip) 499 + return -EINVAL; 500 + 501 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 502 + thermal->regs = devm_ioremap_resource(&pdev->dev, res); 503 + if (IS_ERR(thermal->regs)) 504 + return PTR_ERR(thermal->regs); 505 + 506 + thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb"); 507 + if (IS_ERR(thermal->reset)) { 508 + error = PTR_ERR(thermal->reset); 509 + dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error); 510 + return error; 511 + } 512 + 513 + thermal->clk = devm_clk_get(&pdev->dev, "tsadc"); 514 + if (IS_ERR(thermal->clk)) { 515 + error = PTR_ERR(thermal->clk); 516 + dev_err(&pdev->dev, "failed to get tsadc clock: %d\n", error); 517 + return error; 518 + } 519 + 520 + thermal->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 521 + if (IS_ERR(thermal->pclk)) { 522 + error = PTR_ERR(thermal->clk); 523 + dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n", 524 + error); 525 + return error; 526 + } 527 + 528 + error = clk_prepare_enable(thermal->clk); 529 + if (error) { 530 + dev_err(&pdev->dev, "failed to enable converter clock: %d\n", 531 + error); 532 + return error; 533 + } 534 + 535 + error = clk_prepare_enable(thermal->pclk); 536 + if (error) { 537 + dev_err(&pdev->dev, "failed to enable pclk: %d\n", error); 538 + goto err_disable_clk; 539 + } 540 + 541 + rockchip_thermal_reset_controller(thermal->reset); 542 + 543 + error = rockchip_configure_from_dt(&pdev->dev, np, thermal); 544 + if (error) { 545 + dev_err(&pdev->dev, "failed to parse device tree data: %d\n", 546 + error); 547 + goto err_disable_pclk; 548 + } 549 + 550 + thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 551 + 552 + error = rockchip_thermal_register_sensor(pdev, thermal, 553 + &thermal->sensors[0], 554 + SENSOR_CPU); 555 + if (error) { 556 + dev_err(&pdev->dev, 557 + "failed to register CPU thermal sensor: %d\n", error); 558 + goto err_disable_pclk; 559 + } 560 + 561 + error = rockchip_thermal_register_sensor(pdev, thermal, 562 + &thermal->sensors[1], 563 + SENSOR_GPU); 564 + if (error) { 565 + dev_err(&pdev->dev, 566 + "failed to register GPU thermal sensor: %d\n", error); 567 + goto err_unregister_cpu_sensor; 568 + } 569 + 570 + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, 571 + &rockchip_thermal_alarm_irq_thread, 572 + IRQF_ONESHOT, 573 + "rockchip_thermal", thermal); 574 + if (error) { 575 + dev_err(&pdev->dev, 576 + "failed to request tsadc irq: %d\n", error); 577 + goto err_unregister_gpu_sensor; 578 + } 579 + 580 + thermal->chip->control(thermal->regs, true); 581 + 582 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) 583 + rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 584 + 585 + platform_set_drvdata(pdev, thermal); 586 + 587 + return 0; 588 + 589 + err_unregister_gpu_sensor: 590 + thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd); 591 + err_unregister_cpu_sensor: 592 + thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd); 593 + err_disable_pclk: 594 + clk_disable_unprepare(thermal->pclk); 595 + err_disable_clk: 596 + clk_disable_unprepare(thermal->clk); 597 + 598 + return error; 599 + } 600 + 601 + static int rockchip_thermal_remove(struct platform_device *pdev) 602 + { 603 + struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 604 + int i; 605 + 606 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) { 607 + struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; 608 + 609 + rockchip_thermal_toggle_sensor(sensor, false); 610 + thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); 611 + } 612 + 613 + thermal->chip->control(thermal->regs, false); 614 + 615 + clk_disable_unprepare(thermal->pclk); 616 + clk_disable_unprepare(thermal->clk); 617 + 618 + return 0; 619 + } 620 + 621 + static int __maybe_unused rockchip_thermal_suspend(struct device *dev) 622 + { 623 + struct platform_device *pdev = to_platform_device(dev); 624 + struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 625 + int i; 626 + 627 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) 628 + rockchip_thermal_toggle_sensor(&thermal->sensors[i], false); 629 + 630 + thermal->chip->control(thermal->regs, false); 631 + 632 + clk_disable(thermal->pclk); 633 + clk_disable(thermal->clk); 634 + 635 + return 0; 636 + } 637 + 638 + static int __maybe_unused rockchip_thermal_resume(struct device *dev) 639 + { 640 + struct platform_device *pdev = to_platform_device(dev); 641 + struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev); 642 + int i; 643 + int error; 644 + 645 + error = clk_enable(thermal->clk); 646 + if (error) 647 + return error; 648 + 649 + error = clk_enable(thermal->pclk); 650 + if (error) 651 + return error; 652 + 653 + rockchip_thermal_reset_controller(thermal->reset); 654 + 655 + thermal->chip->initialize(thermal->regs, thermal->tshut_polarity); 656 + 657 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) { 658 + enum sensor_id id = thermal->sensors[i].id; 659 + 660 + thermal->chip->set_tshut_mode(id, thermal->regs, 661 + thermal->tshut_mode); 662 + thermal->chip->set_tshut_temp(id, thermal->regs, 663 + thermal->tshut_temp); 664 + } 665 + 666 + thermal->chip->control(thermal->regs, true); 667 + 668 + for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) 669 + rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); 670 + 671 + return 0; 672 + } 673 + 674 + static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops, 675 + rockchip_thermal_suspend, rockchip_thermal_resume); 676 + 677 + static struct platform_driver rockchip_thermal_driver = { 678 + .driver = { 679 + .name = "rockchip-thermal", 680 + .owner = THIS_MODULE, 681 + .pm = &rockchip_thermal_pm_ops, 682 + .of_match_table = of_rockchip_thermal_match, 683 + }, 684 + .probe = rockchip_thermal_probe, 685 + .remove = rockchip_thermal_remove, 686 + }; 687 + 688 + module_platform_driver(rockchip_thermal_driver); 689 + 690 + MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver"); 691 + MODULE_AUTHOR("Rockchip, Inc."); 692 + MODULE_LICENSE("GPL v2"); 693 + MODULE_ALIAS("platform:rockchip-thermal");
-1
drivers/thermal/samsung/exynos_thermal_common.h
··· 27 27 #define SENSOR_NAME_LEN 16 28 28 #define MAX_TRIP_COUNT 8 29 29 #define MAX_COOLING_DEVICE 4 30 - #define MAX_TRIMINFO_CTRL_REG 2 31 30 32 31 #define ACTIVE_INTERVAL 500 33 32 #define IDLE_INTERVAL 10000
+469 -225
drivers/thermal/samsung/exynos_tmu.c
··· 33 33 34 34 #include "exynos_thermal_common.h" 35 35 #include "exynos_tmu.h" 36 - #include "exynos_tmu_data.h" 36 + 37 + /* Exynos generic registers */ 38 + #define EXYNOS_TMU_REG_TRIMINFO 0x0 39 + #define EXYNOS_TMU_REG_CONTROL 0x20 40 + #define EXYNOS_TMU_REG_STATUS 0x28 41 + #define EXYNOS_TMU_REG_CURRENT_TEMP 0x40 42 + #define EXYNOS_TMU_REG_INTEN 0x70 43 + #define EXYNOS_TMU_REG_INTSTAT 0x74 44 + #define EXYNOS_TMU_REG_INTCLEAR 0x78 45 + 46 + #define EXYNOS_TMU_TEMP_MASK 0xff 47 + #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24 48 + #define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f 49 + #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf 50 + #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8 51 + #define EXYNOS_TMU_CORE_EN_SHIFT 0 52 + 53 + /* Exynos3250 specific registers */ 54 + #define EXYNOS_TMU_TRIMINFO_CON1 0x10 55 + 56 + /* Exynos4210 specific registers */ 57 + #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44 58 + #define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50 59 + 60 + /* Exynos5250, Exynos4412, Exynos3250 specific registers */ 61 + #define EXYNOS_TMU_TRIMINFO_CON2 0x14 62 + #define EXYNOS_THD_TEMP_RISE 0x50 63 + #define EXYNOS_THD_TEMP_FALL 0x54 64 + #define EXYNOS_EMUL_CON 0x80 65 + 66 + #define EXYNOS_TRIMINFO_RELOAD_ENABLE 1 67 + #define EXYNOS_TRIMINFO_25_SHIFT 0 68 + #define EXYNOS_TRIMINFO_85_SHIFT 8 69 + #define EXYNOS_TMU_TRIP_MODE_SHIFT 13 70 + #define EXYNOS_TMU_TRIP_MODE_MASK 0x7 71 + #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12 72 + 73 + #define EXYNOS_TMU_INTEN_RISE0_SHIFT 0 74 + #define EXYNOS_TMU_INTEN_RISE1_SHIFT 4 75 + #define EXYNOS_TMU_INTEN_RISE2_SHIFT 8 76 + #define EXYNOS_TMU_INTEN_RISE3_SHIFT 12 77 + #define EXYNOS_TMU_INTEN_FALL0_SHIFT 16 78 + 79 + #define EXYNOS_EMUL_TIME 0x57F0 80 + #define EXYNOS_EMUL_TIME_MASK 0xffff 81 + #define EXYNOS_EMUL_TIME_SHIFT 16 82 + #define EXYNOS_EMUL_DATA_SHIFT 8 83 + #define EXYNOS_EMUL_DATA_MASK 0xFF 84 + #define EXYNOS_EMUL_ENABLE 0x1 85 + 86 + /* Exynos5260 specific */ 87 + #define EXYNOS5260_TMU_REG_INTEN 0xC0 88 + #define EXYNOS5260_TMU_REG_INTSTAT 0xC4 89 + #define EXYNOS5260_TMU_REG_INTCLEAR 0xC8 90 + #define EXYNOS5260_EMUL_CON 0x100 91 + 92 + /* Exynos4412 specific */ 93 + #define EXYNOS4412_MUX_ADDR_VALUE 6 94 + #define EXYNOS4412_MUX_ADDR_SHIFT 20 95 + 96 + /*exynos5440 specific registers*/ 97 + #define EXYNOS5440_TMU_S0_7_TRIM 0x000 98 + #define EXYNOS5440_TMU_S0_7_CTRL 0x020 99 + #define EXYNOS5440_TMU_S0_7_DEBUG 0x040 100 + #define EXYNOS5440_TMU_S0_7_TEMP 0x0f0 101 + #define EXYNOS5440_TMU_S0_7_TH0 0x110 102 + #define EXYNOS5440_TMU_S0_7_TH1 0x130 103 + #define EXYNOS5440_TMU_S0_7_TH2 0x150 104 + #define EXYNOS5440_TMU_S0_7_IRQEN 0x210 105 + #define EXYNOS5440_TMU_S0_7_IRQ 0x230 106 + /* exynos5440 common registers */ 107 + #define EXYNOS5440_TMU_IRQ_STATUS 0x000 108 + #define EXYNOS5440_TMU_PMIN 0x004 109 + 110 + #define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0 111 + #define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1 112 + #define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2 113 + #define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3 114 + #define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4 115 + #define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 116 + #define EXYNOS5440_EFUSE_SWAP_OFFSET 8 37 117 38 118 /** 39 119 * struct exynos_tmu_data : A structure to hold the private data of the TMU ··· 132 52 * @temp_error2: fused value of the second point trim. 133 53 * @regulator: pointer to the TMU regulator structure. 134 54 * @reg_conf: pointer to structure to register with core thermal. 55 + * @tmu_initialize: SoC specific TMU initialization method 56 + * @tmu_control: SoC specific TMU control method 57 + * @tmu_read: SoC specific TMU temperature read method 58 + * @tmu_set_emulation: SoC specific TMU emulation setting method 59 + * @tmu_clear_irqs: SoC specific TMU interrupts clearing method 135 60 */ 136 61 struct exynos_tmu_data { 137 62 int id; ··· 151 66 u8 temp_error1, temp_error2; 152 67 struct regulator *regulator; 153 68 struct thermal_sensor_conf *reg_conf; 69 + int (*tmu_initialize)(struct platform_device *pdev); 70 + void (*tmu_control)(struct platform_device *pdev, bool on); 71 + int (*tmu_read)(struct exynos_tmu_data *data); 72 + void (*tmu_set_emulation)(struct exynos_tmu_data *data, 73 + unsigned long temp); 74 + void (*tmu_clear_irqs)(struct exynos_tmu_data *data); 154 75 }; 155 76 156 77 /* ··· 213 122 return temp; 214 123 } 215 124 216 - static void exynos_tmu_clear_irqs(struct exynos_tmu_data *data) 125 + static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info) 217 126 { 218 - const struct exynos_tmu_registers *reg = data->pdata->registers; 219 - unsigned int val_irq; 220 - 221 - val_irq = readl(data->base + reg->tmu_intstat); 222 - /* 223 - * Clear the interrupts. Please note that the documentation for 224 - * Exynos3250, Exynos4412, Exynos5250 and Exynos5260 incorrectly 225 - * states that INTCLEAR register has a different placing of bits 226 - * responsible for FALL IRQs than INTSTAT register. Exynos5420 227 - * and Exynos5440 documentation is correct (Exynos4210 doesn't 228 - * support FALL IRQs at all). 229 - */ 230 - writel(val_irq, data->base + reg->tmu_intclear); 231 - } 232 - 233 - static int exynos_tmu_initialize(struct platform_device *pdev) 234 - { 235 - struct exynos_tmu_data *data = platform_get_drvdata(pdev); 236 127 struct exynos_tmu_platform_data *pdata = data->pdata; 237 - const struct exynos_tmu_registers *reg = pdata->registers; 238 - unsigned int status, trim_info = 0, con, ctrl; 239 - unsigned int rising_threshold = 0, falling_threshold = 0; 240 - int ret = 0, threshold_code, i; 241 128 242 - mutex_lock(&data->lock); 243 - clk_enable(data->clk); 244 - if (!IS_ERR(data->clk_sec)) 245 - clk_enable(data->clk_sec); 246 - 247 - if (TMU_SUPPORTS(pdata, READY_STATUS)) { 248 - status = readb(data->base + reg->tmu_status); 249 - if (!status) { 250 - ret = -EBUSY; 251 - goto out; 252 - } 253 - } 254 - 255 - if (TMU_SUPPORTS(pdata, TRIM_RELOAD)) { 256 - for (i = 0; i < reg->triminfo_ctrl_count; i++) { 257 - if (pdata->triminfo_reload[i]) { 258 - ctrl = readl(data->base + 259 - reg->triminfo_ctrl[i]); 260 - ctrl |= pdata->triminfo_reload[i]; 261 - writel(ctrl, data->base + 262 - reg->triminfo_ctrl[i]); 263 - } 264 - } 265 - } 266 - 267 - /* Save trimming info in order to perform calibration */ 268 - if (data->soc == SOC_ARCH_EXYNOS5440) { 269 - /* 270 - * For exynos5440 soc triminfo value is swapped between TMU0 and 271 - * TMU2, so the below logic is needed. 272 - */ 273 - switch (data->id) { 274 - case 0: 275 - trim_info = readl(data->base + 276 - EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 277 - break; 278 - case 1: 279 - trim_info = readl(data->base + reg->triminfo_data); 280 - break; 281 - case 2: 282 - trim_info = readl(data->base - 283 - EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data); 284 - } 285 - } else { 286 - /* On exynos5420 the triminfo register is in the shared space */ 287 - if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) 288 - trim_info = readl(data->base_second + 289 - reg->triminfo_data); 290 - else 291 - trim_info = readl(data->base + reg->triminfo_data); 292 - } 293 129 data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK; 294 130 data->temp_error2 = ((trim_info >> EXYNOS_TRIMINFO_85_SHIFT) & 295 131 EXYNOS_TMU_TEMP_MASK); ··· 230 212 data->temp_error2 = 231 213 (pdata->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) & 232 214 EXYNOS_TMU_TEMP_MASK; 215 + } 233 216 234 - rising_threshold = readl(data->base + reg->threshold_th0); 217 + static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling) 218 + { 219 + struct exynos_tmu_platform_data *pdata = data->pdata; 220 + int i; 235 221 236 - if (data->soc == SOC_ARCH_EXYNOS4210) { 237 - /* Write temperature code for threshold */ 238 - threshold_code = temp_to_code(data, pdata->threshold); 239 - writeb(threshold_code, 240 - data->base + reg->threshold_temp); 241 - for (i = 0; i < pdata->non_hw_trigger_levels; i++) 242 - writeb(pdata->trigger_levels[i], data->base + 243 - reg->threshold_th0 + i * sizeof(reg->threshold_th0)); 222 + for (i = 0; i < pdata->non_hw_trigger_levels; i++) { 223 + u8 temp = pdata->trigger_levels[i]; 244 224 245 - exynos_tmu_clear_irqs(data); 246 - } else { 247 - /* Write temperature code for rising and falling threshold */ 248 - for (i = 0; i < pdata->non_hw_trigger_levels; i++) { 249 - threshold_code = temp_to_code(data, 250 - pdata->trigger_levels[i]); 251 - rising_threshold &= ~(0xff << 8 * i); 252 - rising_threshold |= threshold_code << 8 * i; 253 - if (pdata->threshold_falling) { 254 - threshold_code = temp_to_code(data, 255 - pdata->trigger_levels[i] - 256 - pdata->threshold_falling); 257 - falling_threshold |= threshold_code << 8 * i; 258 - } 259 - } 225 + if (falling) 226 + temp -= pdata->threshold_falling; 227 + else 228 + threshold &= ~(0xff << 8 * i); 260 229 261 - writel(rising_threshold, 262 - data->base + reg->threshold_th0); 263 - writel(falling_threshold, 264 - data->base + reg->threshold_th1); 265 - 266 - exynos_tmu_clear_irqs(data); 267 - 268 - /* if last threshold limit is also present */ 269 - i = pdata->max_trigger_level - 1; 270 - if (pdata->trigger_levels[i] && 271 - (pdata->trigger_type[i] == HW_TRIP)) { 272 - threshold_code = temp_to_code(data, 273 - pdata->trigger_levels[i]); 274 - if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) { 275 - /* 1-4 level to be assigned in th0 reg */ 276 - rising_threshold &= ~(0xff << 8 * i); 277 - rising_threshold |= threshold_code << 8 * i; 278 - writel(rising_threshold, 279 - data->base + reg->threshold_th0); 280 - } else if (i == EXYNOS_MAX_TRIGGER_PER_REG) { 281 - /* 5th level to be assigned in th2 reg */ 282 - rising_threshold = 283 - threshold_code << reg->threshold_th3_l0_shift; 284 - writel(rising_threshold, 285 - data->base + reg->threshold_th2); 286 - } 287 - con = readl(data->base + reg->tmu_ctrl); 288 - con |= (1 << reg->therm_trip_en_shift); 289 - writel(con, data->base + reg->tmu_ctrl); 290 - } 230 + threshold |= temp_to_code(data, temp) << 8 * i; 291 231 } 292 - /*Clear the PMIN in the common TMU register*/ 293 - if (reg->tmu_pmin && !data->id) 294 - writel(0, data->base_second + reg->tmu_pmin); 295 - out: 232 + 233 + return threshold; 234 + } 235 + 236 + static int exynos_tmu_initialize(struct platform_device *pdev) 237 + { 238 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 239 + int ret; 240 + 241 + mutex_lock(&data->lock); 242 + clk_enable(data->clk); 243 + if (!IS_ERR(data->clk_sec)) 244 + clk_enable(data->clk_sec); 245 + ret = data->tmu_initialize(pdev); 296 246 clk_disable(data->clk); 297 247 mutex_unlock(&data->lock); 298 248 if (!IS_ERR(data->clk_sec)) ··· 269 283 return ret; 270 284 } 271 285 272 - static void exynos_tmu_control(struct platform_device *pdev, bool on) 286 + static u32 get_con_reg(struct exynos_tmu_data *data, u32 con) 273 287 { 274 - struct exynos_tmu_data *data = platform_get_drvdata(pdev); 275 288 struct exynos_tmu_platform_data *pdata = data->pdata; 276 - const struct exynos_tmu_registers *reg = pdata->registers; 277 - unsigned int con, interrupt_en; 278 289 279 - mutex_lock(&data->lock); 280 - clk_enable(data->clk); 281 - 282 - con = readl(data->base + reg->tmu_ctrl); 283 - 284 - if (pdata->test_mux) 285 - con |= (pdata->test_mux << reg->test_mux_addr_shift); 290 + if (data->soc == SOC_ARCH_EXYNOS4412 || 291 + data->soc == SOC_ARCH_EXYNOS3250) 292 + con |= (EXYNOS4412_MUX_ADDR_VALUE << EXYNOS4412_MUX_ADDR_SHIFT); 286 293 287 294 con &= ~(EXYNOS_TMU_REF_VOLTAGE_MASK << EXYNOS_TMU_REF_VOLTAGE_SHIFT); 288 295 con |= pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT; ··· 284 305 con |= (pdata->gain << EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT); 285 306 286 307 if (pdata->noise_cancel_mode) { 287 - con &= ~(reg->therm_trip_mode_mask << 288 - reg->therm_trip_mode_shift); 289 - con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift); 308 + con &= ~(EXYNOS_TMU_TRIP_MODE_MASK << EXYNOS_TMU_TRIP_MODE_SHIFT); 309 + con |= (pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT); 290 310 } 311 + 312 + return con; 313 + } 314 + 315 + static void exynos_tmu_control(struct platform_device *pdev, bool on) 316 + { 317 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 318 + 319 + mutex_lock(&data->lock); 320 + clk_enable(data->clk); 321 + data->tmu_control(pdev, on); 322 + clk_disable(data->clk); 323 + mutex_unlock(&data->lock); 324 + } 325 + 326 + static int exynos4210_tmu_initialize(struct platform_device *pdev) 327 + { 328 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 329 + struct exynos_tmu_platform_data *pdata = data->pdata; 330 + unsigned int status; 331 + int ret = 0, threshold_code, i; 332 + 333 + status = readb(data->base + EXYNOS_TMU_REG_STATUS); 334 + if (!status) { 335 + ret = -EBUSY; 336 + goto out; 337 + } 338 + 339 + sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO)); 340 + 341 + /* Write temperature code for threshold */ 342 + threshold_code = temp_to_code(data, pdata->threshold); 343 + writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP); 344 + 345 + for (i = 0; i < pdata->non_hw_trigger_levels; i++) 346 + writeb(pdata->trigger_levels[i], data->base + 347 + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4); 348 + 349 + data->tmu_clear_irqs(data); 350 + out: 351 + return ret; 352 + } 353 + 354 + static int exynos4412_tmu_initialize(struct platform_device *pdev) 355 + { 356 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 357 + struct exynos_tmu_platform_data *pdata = data->pdata; 358 + unsigned int status, trim_info, con, ctrl, rising_threshold; 359 + int ret = 0, threshold_code, i; 360 + 361 + status = readb(data->base + EXYNOS_TMU_REG_STATUS); 362 + if (!status) { 363 + ret = -EBUSY; 364 + goto out; 365 + } 366 + 367 + if (data->soc == SOC_ARCH_EXYNOS3250 || 368 + data->soc == SOC_ARCH_EXYNOS4412 || 369 + data->soc == SOC_ARCH_EXYNOS5250) { 370 + if (data->soc == SOC_ARCH_EXYNOS3250) { 371 + ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON1); 372 + ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE; 373 + writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON1); 374 + } 375 + ctrl = readl(data->base + EXYNOS_TMU_TRIMINFO_CON2); 376 + ctrl |= EXYNOS_TRIMINFO_RELOAD_ENABLE; 377 + writel(ctrl, data->base + EXYNOS_TMU_TRIMINFO_CON2); 378 + } 379 + 380 + /* On exynos5420 the triminfo register is in the shared space */ 381 + if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) 382 + trim_info = readl(data->base_second + EXYNOS_TMU_REG_TRIMINFO); 383 + else 384 + trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); 385 + 386 + sanitize_temp_error(data, trim_info); 387 + 388 + /* Write temperature code for rising and falling threshold */ 389 + rising_threshold = readl(data->base + EXYNOS_THD_TEMP_RISE); 390 + rising_threshold = get_th_reg(data, rising_threshold, false); 391 + writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); 392 + writel(get_th_reg(data, 0, true), data->base + EXYNOS_THD_TEMP_FALL); 393 + 394 + data->tmu_clear_irqs(data); 395 + 396 + /* if last threshold limit is also present */ 397 + i = pdata->max_trigger_level - 1; 398 + if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) { 399 + threshold_code = temp_to_code(data, pdata->trigger_levels[i]); 400 + /* 1-4 level to be assigned in th0 reg */ 401 + rising_threshold &= ~(0xff << 8 * i); 402 + rising_threshold |= threshold_code << 8 * i; 403 + writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE); 404 + con = readl(data->base + EXYNOS_TMU_REG_CONTROL); 405 + con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); 406 + writel(con, data->base + EXYNOS_TMU_REG_CONTROL); 407 + } 408 + out: 409 + return ret; 410 + } 411 + 412 + static int exynos5440_tmu_initialize(struct platform_device *pdev) 413 + { 414 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 415 + struct exynos_tmu_platform_data *pdata = data->pdata; 416 + unsigned int trim_info = 0, con, rising_threshold; 417 + int ret = 0, threshold_code, i; 418 + 419 + /* 420 + * For exynos5440 soc triminfo value is swapped between TMU0 and 421 + * TMU2, so the below logic is needed. 422 + */ 423 + switch (data->id) { 424 + case 0: 425 + trim_info = readl(data->base + EXYNOS5440_EFUSE_SWAP_OFFSET + 426 + EXYNOS5440_TMU_S0_7_TRIM); 427 + break; 428 + case 1: 429 + trim_info = readl(data->base + EXYNOS5440_TMU_S0_7_TRIM); 430 + break; 431 + case 2: 432 + trim_info = readl(data->base - EXYNOS5440_EFUSE_SWAP_OFFSET + 433 + EXYNOS5440_TMU_S0_7_TRIM); 434 + } 435 + sanitize_temp_error(data, trim_info); 436 + 437 + /* Write temperature code for rising and falling threshold */ 438 + rising_threshold = readl(data->base + EXYNOS5440_TMU_S0_7_TH0); 439 + rising_threshold = get_th_reg(data, rising_threshold, false); 440 + writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH0); 441 + writel(0, data->base + EXYNOS5440_TMU_S0_7_TH1); 442 + 443 + data->tmu_clear_irqs(data); 444 + 445 + /* if last threshold limit is also present */ 446 + i = pdata->max_trigger_level - 1; 447 + if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) { 448 + threshold_code = temp_to_code(data, pdata->trigger_levels[i]); 449 + /* 5th level to be assigned in th2 reg */ 450 + rising_threshold = 451 + threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT; 452 + writel(rising_threshold, data->base + EXYNOS5440_TMU_S0_7_TH2); 453 + con = readl(data->base + EXYNOS5440_TMU_S0_7_CTRL); 454 + con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT); 455 + writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); 456 + } 457 + /* Clear the PMIN in the common TMU register */ 458 + if (!data->id) 459 + writel(0, data->base_second + EXYNOS5440_TMU_PMIN); 460 + return ret; 461 + } 462 + 463 + static void exynos4210_tmu_control(struct platform_device *pdev, bool on) 464 + { 465 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 466 + struct exynos_tmu_platform_data *pdata = data->pdata; 467 + unsigned int con, interrupt_en; 468 + 469 + con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); 291 470 292 471 if (on) { 293 472 con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); 294 473 interrupt_en = 295 - pdata->trigger_enable[3] << reg->inten_rise3_shift | 296 - pdata->trigger_enable[2] << reg->inten_rise2_shift | 297 - pdata->trigger_enable[1] << reg->inten_rise1_shift | 298 - pdata->trigger_enable[0] << reg->inten_rise0_shift; 299 - if (TMU_SUPPORTS(pdata, FALLING_TRIP)) 474 + pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT | 475 + pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT | 476 + pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT | 477 + pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT; 478 + if (data->soc != SOC_ARCH_EXYNOS4210) 300 479 interrupt_en |= 301 - interrupt_en << reg->inten_fall0_shift; 480 + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; 302 481 } else { 303 482 con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); 304 483 interrupt_en = 0; /* Disable all interrupts */ 305 484 } 306 - writel(interrupt_en, data->base + reg->tmu_inten); 307 - writel(con, data->base + reg->tmu_ctrl); 485 + writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN); 486 + writel(con, data->base + EXYNOS_TMU_REG_CONTROL); 487 + } 308 488 309 - clk_disable(data->clk); 310 - mutex_unlock(&data->lock); 489 + static void exynos5440_tmu_control(struct platform_device *pdev, bool on) 490 + { 491 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 492 + struct exynos_tmu_platform_data *pdata = data->pdata; 493 + unsigned int con, interrupt_en; 494 + 495 + con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL)); 496 + 497 + if (on) { 498 + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); 499 + interrupt_en = 500 + pdata->trigger_enable[3] << EXYNOS5440_TMU_INTEN_RISE3_SHIFT | 501 + pdata->trigger_enable[2] << EXYNOS5440_TMU_INTEN_RISE2_SHIFT | 502 + pdata->trigger_enable[1] << EXYNOS5440_TMU_INTEN_RISE1_SHIFT | 503 + pdata->trigger_enable[0] << EXYNOS5440_TMU_INTEN_RISE0_SHIFT; 504 + interrupt_en |= interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT; 505 + } else { 506 + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); 507 + interrupt_en = 0; /* Disable all interrupts */ 508 + } 509 + writel(interrupt_en, data->base + EXYNOS5440_TMU_S0_7_IRQEN); 510 + writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); 311 511 } 312 512 313 513 static int exynos_tmu_read(struct exynos_tmu_data *data) 314 514 { 315 - struct exynos_tmu_platform_data *pdata = data->pdata; 316 - const struct exynos_tmu_registers *reg = pdata->registers; 317 - u8 temp_code; 318 - int temp; 515 + int ret; 319 516 320 517 mutex_lock(&data->lock); 321 518 clk_enable(data->clk); 322 - 323 - temp_code = readb(data->base + reg->tmu_cur_temp); 324 - 325 - if (data->soc == SOC_ARCH_EXYNOS4210) 326 - /* temp_code should range between 75 and 175 */ 327 - if (temp_code < 75 || temp_code > 175) { 328 - temp = -ENODATA; 329 - goto out; 330 - } 331 - 332 - temp = code_to_temp(data, temp_code); 333 - out: 519 + ret = data->tmu_read(data); 520 + if (ret >= 0) 521 + ret = code_to_temp(data, ret); 334 522 clk_disable(data->clk); 335 523 mutex_unlock(&data->lock); 336 524 337 - return temp; 525 + return ret; 338 526 } 339 527 340 528 #ifdef CONFIG_THERMAL_EMULATION 529 + static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, 530 + unsigned long temp) 531 + { 532 + if (temp) { 533 + temp /= MCELSIUS; 534 + 535 + if (data->soc != SOC_ARCH_EXYNOS5440) { 536 + val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); 537 + val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); 538 + } 539 + val &= ~(EXYNOS_EMUL_DATA_MASK << EXYNOS_EMUL_DATA_SHIFT); 540 + val |= (temp_to_code(data, temp) << EXYNOS_EMUL_DATA_SHIFT) | 541 + EXYNOS_EMUL_ENABLE; 542 + } else { 543 + val &= ~EXYNOS_EMUL_ENABLE; 544 + } 545 + 546 + return val; 547 + } 548 + 549 + static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, 550 + unsigned long temp) 551 + { 552 + unsigned int val; 553 + u32 emul_con; 554 + 555 + if (data->soc == SOC_ARCH_EXYNOS5260) 556 + emul_con = EXYNOS5260_EMUL_CON; 557 + else 558 + emul_con = EXYNOS_EMUL_CON; 559 + 560 + val = readl(data->base + emul_con); 561 + val = get_emul_con_reg(data, val, temp); 562 + writel(val, data->base + emul_con); 563 + } 564 + 565 + static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data, 566 + unsigned long temp) 567 + { 568 + unsigned int val; 569 + 570 + val = readl(data->base + EXYNOS5440_TMU_S0_7_DEBUG); 571 + val = get_emul_con_reg(data, val, temp); 572 + writel(val, data->base + EXYNOS5440_TMU_S0_7_DEBUG); 573 + } 574 + 341 575 static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) 342 576 { 343 577 struct exynos_tmu_data *data = drv_data; 344 - struct exynos_tmu_platform_data *pdata = data->pdata; 345 - const struct exynos_tmu_registers *reg = pdata->registers; 346 - unsigned int val; 347 578 int ret = -EINVAL; 348 579 349 - if (!TMU_SUPPORTS(pdata, EMULATION)) 580 + if (data->soc == SOC_ARCH_EXYNOS4210) 350 581 goto out; 351 582 352 583 if (temp && temp < MCELSIUS) ··· 564 375 565 376 mutex_lock(&data->lock); 566 377 clk_enable(data->clk); 567 - 568 - val = readl(data->base + reg->emul_con); 569 - 570 - if (temp) { 571 - temp /= MCELSIUS; 572 - 573 - if (TMU_SUPPORTS(pdata, EMUL_TIME)) { 574 - val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift); 575 - val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift); 576 - } 577 - val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift); 578 - val |= (temp_to_code(data, temp) << reg->emul_temp_shift) | 579 - EXYNOS_EMUL_ENABLE; 580 - } else { 581 - val &= ~EXYNOS_EMUL_ENABLE; 582 - } 583 - 584 - writel(val, data->base + reg->emul_con); 585 - 378 + data->tmu_set_emulation(data, temp); 586 379 clk_disable(data->clk); 587 380 mutex_unlock(&data->lock); 588 381 return 0; ··· 572 401 return ret; 573 402 } 574 403 #else 404 + #define exynos4412_tmu_set_emulation NULL 405 + #define exynos5440_tmu_set_emulation NULL 575 406 static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) 576 407 { return -EINVAL; } 577 408 #endif/*CONFIG_THERMAL_EMULATION*/ 409 + 410 + static int exynos4210_tmu_read(struct exynos_tmu_data *data) 411 + { 412 + int ret = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP); 413 + 414 + /* "temp_code" should range between 75 and 175 */ 415 + return (ret < 75 || ret > 175) ? -ENODATA : ret; 416 + } 417 + 418 + static int exynos4412_tmu_read(struct exynos_tmu_data *data) 419 + { 420 + return readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP); 421 + } 422 + 423 + static int exynos5440_tmu_read(struct exynos_tmu_data *data) 424 + { 425 + return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP); 426 + } 578 427 579 428 static void exynos_tmu_work(struct work_struct *work) 580 429 { 581 430 struct exynos_tmu_data *data = container_of(work, 582 431 struct exynos_tmu_data, irq_work); 583 - struct exynos_tmu_platform_data *pdata = data->pdata; 584 - const struct exynos_tmu_registers *reg = pdata->registers; 585 432 unsigned int val_type; 586 433 587 434 if (!IS_ERR(data->clk_sec)) 588 435 clk_enable(data->clk_sec); 589 436 /* Find which sensor generated this interrupt */ 590 - if (reg->tmu_irqstatus) { 591 - val_type = readl(data->base_second + reg->tmu_irqstatus); 437 + if (data->soc == SOC_ARCH_EXYNOS5440) { 438 + val_type = readl(data->base_second + EXYNOS5440_TMU_IRQ_STATUS); 592 439 if (!((val_type >> data->id) & 0x1)) 593 440 goto out; 594 441 } ··· 618 429 clk_enable(data->clk); 619 430 620 431 /* TODO: take action based on particular interrupt */ 621 - exynos_tmu_clear_irqs(data); 432 + data->tmu_clear_irqs(data); 622 433 623 434 clk_disable(data->clk); 624 435 mutex_unlock(&data->lock); 625 436 out: 626 437 enable_irq(data->irq); 438 + } 439 + 440 + static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) 441 + { 442 + unsigned int val_irq; 443 + u32 tmu_intstat, tmu_intclear; 444 + 445 + if (data->soc == SOC_ARCH_EXYNOS5260) { 446 + tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT; 447 + tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR; 448 + } else { 449 + tmu_intstat = EXYNOS_TMU_REG_INTSTAT; 450 + tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; 451 + } 452 + 453 + val_irq = readl(data->base + tmu_intstat); 454 + /* 455 + * Clear the interrupts. Please note that the documentation for 456 + * Exynos3250, Exynos4412, Exynos5250 and Exynos5260 incorrectly 457 + * states that INTCLEAR register has a different placing of bits 458 + * responsible for FALL IRQs than INTSTAT register. Exynos5420 459 + * and Exynos5440 documentation is correct (Exynos4210 doesn't 460 + * support FALL IRQs at all). 461 + */ 462 + writel(val_irq, data->base + tmu_intclear); 463 + } 464 + 465 + static void exynos5440_tmu_clear_irqs(struct exynos_tmu_data *data) 466 + { 467 + unsigned int val_irq; 468 + 469 + val_irq = readl(data->base + EXYNOS5440_TMU_S0_7_IRQ); 470 + /* clear the interrupts */ 471 + writel(val_irq, data->base + EXYNOS5440_TMU_S0_7_IRQ); 627 472 } 628 473 629 474 static irqreturn_t exynos_tmu_irq(int irq, void *id) ··· 673 450 static const struct of_device_id exynos_tmu_match[] = { 674 451 { 675 452 .compatible = "samsung,exynos3250-tmu", 676 - .data = (void *)EXYNOS3250_TMU_DRV_DATA, 453 + .data = &exynos3250_default_tmu_data, 677 454 }, 678 455 { 679 456 .compatible = "samsung,exynos4210-tmu", 680 - .data = (void *)EXYNOS4210_TMU_DRV_DATA, 457 + .data = &exynos4210_default_tmu_data, 681 458 }, 682 459 { 683 460 .compatible = "samsung,exynos4412-tmu", 684 - .data = (void *)EXYNOS4412_TMU_DRV_DATA, 461 + .data = &exynos4412_default_tmu_data, 685 462 }, 686 463 { 687 464 .compatible = "samsung,exynos5250-tmu", 688 - .data = (void *)EXYNOS5250_TMU_DRV_DATA, 465 + .data = &exynos5250_default_tmu_data, 689 466 }, 690 467 { 691 468 .compatible = "samsung,exynos5260-tmu", 692 - .data = (void *)EXYNOS5260_TMU_DRV_DATA, 469 + .data = &exynos5260_default_tmu_data, 693 470 }, 694 471 { 695 472 .compatible = "samsung,exynos5420-tmu", 696 - .data = (void *)EXYNOS5420_TMU_DRV_DATA, 473 + .data = &exynos5420_default_tmu_data, 697 474 }, 698 475 { 699 476 .compatible = "samsung,exynos5420-tmu-ext-triminfo", 700 - .data = (void *)EXYNOS5420_TMU_DRV_DATA, 477 + .data = &exynos5420_default_tmu_data, 701 478 }, 702 479 { 703 480 .compatible = "samsung,exynos5440-tmu", 704 - .data = (void *)EXYNOS5440_TMU_DRV_DATA, 481 + .data = &exynos5440_default_tmu_data, 705 482 }, 706 483 {}, 707 484 }; ··· 776 553 dev_err(&pdev->dev, "No platform init data supplied.\n"); 777 554 return -ENODEV; 778 555 } 556 + 779 557 data->pdata = pdata; 558 + data->soc = pdata->type; 559 + 560 + switch (data->soc) { 561 + case SOC_ARCH_EXYNOS4210: 562 + data->tmu_initialize = exynos4210_tmu_initialize; 563 + data->tmu_control = exynos4210_tmu_control; 564 + data->tmu_read = exynos4210_tmu_read; 565 + data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; 566 + break; 567 + case SOC_ARCH_EXYNOS3250: 568 + case SOC_ARCH_EXYNOS4412: 569 + case SOC_ARCH_EXYNOS5250: 570 + case SOC_ARCH_EXYNOS5260: 571 + case SOC_ARCH_EXYNOS5420: 572 + case SOC_ARCH_EXYNOS5420_TRIMINFO: 573 + data->tmu_initialize = exynos4412_tmu_initialize; 574 + data->tmu_control = exynos4210_tmu_control; 575 + data->tmu_read = exynos4412_tmu_read; 576 + data->tmu_set_emulation = exynos4412_tmu_set_emulation; 577 + data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; 578 + break; 579 + case SOC_ARCH_EXYNOS5440: 580 + data->tmu_initialize = exynos5440_tmu_initialize; 581 + data->tmu_control = exynos5440_tmu_control; 582 + data->tmu_read = exynos5440_tmu_read; 583 + data->tmu_set_emulation = exynos5440_tmu_set_emulation; 584 + data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; 585 + break; 586 + default: 587 + dev_err(&pdev->dev, "Platform not supported\n"); 588 + return -EINVAL; 589 + } 590 + 780 591 /* 781 592 * Check if the TMU shares some registers and then try to map the 782 593 * memory of common registers. 783 594 */ 784 - if (!TMU_SUPPORTS(pdata, ADDRESS_MULTIPLE)) 595 + if (data->soc != SOC_ARCH_EXYNOS5420_TRIMINFO && 596 + data->soc != SOC_ARCH_EXYNOS5440) 785 597 return 0; 786 598 787 599 if (of_address_to_resource(pdev->dev.of_node, 1, &res)) { ··· 881 623 if (ret) { 882 624 dev_err(&pdev->dev, "Failed to get clock\n"); 883 625 goto err_clk_sec; 884 - } 885 - 886 - if (pdata->type == SOC_ARCH_EXYNOS3250 || 887 - pdata->type == SOC_ARCH_EXYNOS4210 || 888 - pdata->type == SOC_ARCH_EXYNOS4412 || 889 - pdata->type == SOC_ARCH_EXYNOS5250 || 890 - pdata->type == SOC_ARCH_EXYNOS5260 || 891 - pdata->type == SOC_ARCH_EXYNOS5420_TRIMINFO || 892 - pdata->type == SOC_ARCH_EXYNOS5440) 893 - data->soc = pdata->type; 894 - else { 895 - ret = -EINVAL; 896 - dev_err(&pdev->dev, "Platform not supported\n"); 897 - goto err_clk; 898 626 } 899 627 900 628 ret = exynos_tmu_initialize(pdev);
+9 -114
drivers/thermal/samsung/exynos_tmu.h
··· 40 40 SOC_ARCH_EXYNOS4412, 41 41 SOC_ARCH_EXYNOS5250, 42 42 SOC_ARCH_EXYNOS5260, 43 + SOC_ARCH_EXYNOS5420, 43 44 SOC_ARCH_EXYNOS5420_TRIMINFO, 44 45 SOC_ARCH_EXYNOS5440, 45 - }; 46 - 47 - /** 48 - * EXYNOS TMU supported features. 49 - * TMU_SUPPORT_EMULATION - This features is used to set user defined 50 - * temperature to the TMU controller. 51 - * TMU_SUPPORT_MULTI_INST - This features denotes that the soc 52 - * has many instances of TMU. 53 - * TMU_SUPPORT_TRIM_RELOAD - This features shows that trimming can 54 - * be reloaded. 55 - * TMU_SUPPORT_FALLING_TRIP - This features shows that interrupt can 56 - * be registered for falling trips also. 57 - * TMU_SUPPORT_READY_STATUS - This feature tells that the TMU current 58 - * state(active/idle) can be checked. 59 - * TMU_SUPPORT_EMUL_TIME - This features allows to set next temp emulation 60 - * sample time. 61 - * TMU_SUPPORT_ADDRESS_MULTIPLE - This feature tells that the different TMU 62 - * sensors shares some common registers. 63 - * TMU_SUPPORT - macro to compare the above features with the supplied. 64 - */ 65 - #define TMU_SUPPORT_EMULATION BIT(0) 66 - #define TMU_SUPPORT_MULTI_INST BIT(1) 67 - #define TMU_SUPPORT_TRIM_RELOAD BIT(2) 68 - #define TMU_SUPPORT_FALLING_TRIP BIT(3) 69 - #define TMU_SUPPORT_READY_STATUS BIT(4) 70 - #define TMU_SUPPORT_EMUL_TIME BIT(5) 71 - #define TMU_SUPPORT_ADDRESS_MULTIPLE BIT(6) 72 - 73 - #define TMU_SUPPORTS(a, b) (a->features & TMU_SUPPORT_ ## b) 74 - 75 - /** 76 - * struct exynos_tmu_register - register descriptors to access registers and 77 - * bitfields. The register validity, offsets and bitfield values may vary 78 - * slightly across different exynos SOC's. 79 - * @triminfo_data: register containing 2 pont trimming data 80 - * @triminfo_ctrl: trim info controller register. 81 - * @triminfo_ctrl_count: the number of trim info controller register. 82 - * @tmu_ctrl: TMU main controller register. 83 - * @test_mux_addr_shift: shift bits of test mux address. 84 - * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register. 85 - * @therm_trip_mode_mask: mask bits of tripping mode in tmu_ctrl register. 86 - * @therm_trip_en_shift: shift bits of tripping enable in tmu_ctrl register. 87 - * @tmu_status: register drescribing the TMU status. 88 - * @tmu_cur_temp: register containing the current temperature of the TMU. 89 - * @threshold_temp: register containing the base threshold level. 90 - * @threshold_th0: Register containing first set of rising levels. 91 - * @threshold_th1: Register containing second set of rising levels. 92 - * @threshold_th2: Register containing third set of rising levels. 93 - * @threshold_th3_l0_shift: shift bits of level0 threshold temperature. 94 - * @tmu_inten: register containing the different threshold interrupt 95 - enable bits. 96 - * @inten_rise0_shift: shift bits of rising 0 interrupt bits. 97 - * @inten_rise1_shift: shift bits of rising 1 interrupt bits. 98 - * @inten_rise2_shift: shift bits of rising 2 interrupt bits. 99 - * @inten_rise3_shift: shift bits of rising 3 interrupt bits. 100 - * @inten_fall0_shift: shift bits of falling 0 interrupt bits. 101 - * @tmu_intstat: Register containing the interrupt status values. 102 - * @tmu_intclear: Register for clearing the raised interrupt status. 103 - * @emul_con: TMU emulation controller register. 104 - * @emul_temp_shift: shift bits of emulation temperature. 105 - * @emul_time_shift: shift bits of emulation time. 106 - * @tmu_irqstatus: register to find which TMU generated interrupts. 107 - * @tmu_pmin: register to get/set the Pmin value. 108 - */ 109 - struct exynos_tmu_registers { 110 - u32 triminfo_data; 111 - 112 - u32 triminfo_ctrl[MAX_TRIMINFO_CTRL_REG]; 113 - u32 triminfo_ctrl_count; 114 - 115 - u32 tmu_ctrl; 116 - u32 test_mux_addr_shift; 117 - u32 therm_trip_mode_shift; 118 - u32 therm_trip_mode_mask; 119 - u32 therm_trip_en_shift; 120 - 121 - u32 tmu_status; 122 - 123 - u32 tmu_cur_temp; 124 - 125 - u32 threshold_temp; 126 - 127 - u32 threshold_th0; 128 - u32 threshold_th1; 129 - u32 threshold_th2; 130 - u32 threshold_th3_l0_shift; 131 - 132 - u32 tmu_inten; 133 - u32 inten_rise0_shift; 134 - u32 inten_rise1_shift; 135 - u32 inten_rise2_shift; 136 - u32 inten_rise3_shift; 137 - u32 inten_fall0_shift; 138 - 139 - u32 tmu_intstat; 140 - 141 - u32 tmu_intclear; 142 - 143 - u32 emul_con; 144 - u32 emul_temp_shift; 145 - u32 emul_time_shift; 146 - 147 - u32 tmu_irqstatus; 148 - u32 tmu_pmin; 149 46 }; 150 47 151 48 /** ··· 89 192 * @first_point_trim: temp value of the first point trimming 90 193 * @second_point_trim: temp value of the second point trimming 91 194 * @default_temp_offset: default temperature offset in case of no trimming 92 - * @test_mux; information if SoC supports test MUX 93 - * @triminfo_reload: reload value to read TRIMINFO register 94 195 * @cal_type: calibration type for temperature 95 196 * @freq_clip_table: Table representing frequency reduction percentage. 96 197 * @freq_tab_count: Count of the above table as frequency reduction may 97 198 * applicable to only some of the trigger levels. 98 - * @registers: Pointer to structure containing all the TMU controller registers 99 - * and bitfields shifts and masks. 100 - * @features: a bitfield value indicating the features supported in SOC like 101 - * emulation, multi instance etc 102 199 * 103 200 * This structure is required for configuration of exynos_tmu driver. 104 201 */ ··· 114 223 u8 first_point_trim; 115 224 u8 second_point_trim; 116 225 u8 default_temp_offset; 117 - u8 test_mux; 118 - u8 triminfo_reload[MAX_TRIMINFO_CTRL_REG]; 119 226 120 227 enum calibration_type cal_type; 121 228 enum soc_type type; 122 229 struct freq_clip_table freq_tab[4]; 123 230 unsigned int freq_tab_count; 124 - const struct exynos_tmu_registers *registers; 125 - unsigned int features; 126 231 }; 127 232 128 233 /** ··· 132 245 int tmu_count; 133 246 struct exynos_tmu_platform_data tmu_data[]; 134 247 }; 248 + 249 + extern struct exynos_tmu_init_data const exynos3250_default_tmu_data; 250 + extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; 251 + extern struct exynos_tmu_init_data const exynos4412_default_tmu_data; 252 + extern struct exynos_tmu_init_data const exynos5250_default_tmu_data; 253 + extern struct exynos_tmu_init_data const exynos5260_default_tmu_data; 254 + extern struct exynos_tmu_init_data const exynos5420_default_tmu_data; 255 + extern struct exynos_tmu_init_data const exynos5440_default_tmu_data; 135 256 136 257 #endif /* _EXYNOS_TMU_H */
+8 -231
drivers/thermal/samsung/exynos_tmu_data.c
··· 22 22 23 23 #include "exynos_thermal_common.h" 24 24 #include "exynos_tmu.h" 25 - #include "exynos_tmu_data.h" 26 - 27 - #if defined(CONFIG_CPU_EXYNOS4210) 28 - static const struct exynos_tmu_registers exynos4210_tmu_registers = { 29 - .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 30 - .tmu_ctrl = EXYNOS_TMU_REG_CONTROL, 31 - .tmu_status = EXYNOS_TMU_REG_STATUS, 32 - .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP, 33 - .threshold_temp = EXYNOS4210_TMU_REG_THRESHOLD_TEMP, 34 - .threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0, 35 - .tmu_inten = EXYNOS_TMU_REG_INTEN, 36 - .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT, 37 - .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT, 38 - .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT, 39 - .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT, 40 - .tmu_intstat = EXYNOS_TMU_REG_INTSTAT, 41 - .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR, 42 - }; 43 25 44 26 struct exynos_tmu_init_data const exynos4210_default_tmu_data = { 45 27 .tmu_data = { ··· 57 75 }, 58 76 .freq_tab_count = 2, 59 77 .type = SOC_ARCH_EXYNOS4210, 60 - .registers = &exynos4210_tmu_registers, 61 - .features = TMU_SUPPORT_READY_STATUS, 62 78 }, 63 79 }, 64 80 .tmu_count = 1, 65 - }; 66 - #endif 67 - 68 - #if defined(CONFIG_SOC_EXYNOS3250) 69 - static const struct exynos_tmu_registers exynos3250_tmu_registers = { 70 - .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 71 - .triminfo_ctrl[0] = EXYNOS_TMU_TRIMINFO_CON1, 72 - .triminfo_ctrl[1] = EXYNOS_TMU_TRIMINFO_CON2, 73 - .triminfo_ctrl_count = 2, 74 - .tmu_ctrl = EXYNOS_TMU_REG_CONTROL, 75 - .test_mux_addr_shift = EXYNOS4412_MUX_ADDR_SHIFT, 76 - .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT, 77 - .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK, 78 - .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT, 79 - .tmu_status = EXYNOS_TMU_REG_STATUS, 80 - .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP, 81 - .threshold_th0 = EXYNOS_THD_TEMP_RISE, 82 - .threshold_th1 = EXYNOS_THD_TEMP_FALL, 83 - .tmu_inten = EXYNOS_TMU_REG_INTEN, 84 - .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT, 85 - .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT, 86 - .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT, 87 - .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT, 88 - .tmu_intstat = EXYNOS_TMU_REG_INTSTAT, 89 - .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR, 90 - .emul_con = EXYNOS_EMUL_CON, 91 - .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT, 92 - .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT, 93 81 }; 94 82 95 83 #define EXYNOS3250_TMU_DATA \ ··· 96 144 .freq_clip_max = 400 * 1000, \ 97 145 .temp_level = 95, \ 98 146 }, \ 99 - .freq_tab_count = 2, \ 100 - .triminfo_reload[0] = EXYNOS_TRIMINFO_RELOAD_ENABLE, \ 101 - .triminfo_reload[1] = EXYNOS_TRIMINFO_RELOAD_ENABLE, \ 102 - .registers = &exynos3250_tmu_registers, \ 103 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \ 104 - TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \ 105 - TMU_SUPPORT_EMUL_TIME) 106 - #endif 147 + .freq_tab_count = 2 107 148 108 - #if defined(CONFIG_SOC_EXYNOS3250) 109 149 struct exynos_tmu_init_data const exynos3250_default_tmu_data = { 110 150 .tmu_data = { 111 151 { 112 152 EXYNOS3250_TMU_DATA, 113 153 .type = SOC_ARCH_EXYNOS3250, 114 - .test_mux = EXYNOS4412_MUX_ADDR_VALUE, 115 154 }, 116 155 }, 117 156 .tmu_count = 1, 118 - }; 119 - #endif 120 - 121 - #if defined(CONFIG_SOC_EXYNOS4412) || defined(CONFIG_SOC_EXYNOS5250) 122 - static const struct exynos_tmu_registers exynos4412_tmu_registers = { 123 - .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 124 - .triminfo_ctrl[0] = EXYNOS_TMU_TRIMINFO_CON2, 125 - .triminfo_ctrl_count = 1, 126 - .tmu_ctrl = EXYNOS_TMU_REG_CONTROL, 127 - .test_mux_addr_shift = EXYNOS4412_MUX_ADDR_SHIFT, 128 - .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT, 129 - .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK, 130 - .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT, 131 - .tmu_status = EXYNOS_TMU_REG_STATUS, 132 - .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP, 133 - .threshold_th0 = EXYNOS_THD_TEMP_RISE, 134 - .threshold_th1 = EXYNOS_THD_TEMP_FALL, 135 - .tmu_inten = EXYNOS_TMU_REG_INTEN, 136 - .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT, 137 - .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT, 138 - .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT, 139 - .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT, 140 - .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT, 141 - .tmu_intstat = EXYNOS_TMU_REG_INTSTAT, 142 - .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR, 143 - .emul_con = EXYNOS_EMUL_CON, 144 - .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT, 145 - .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT, 146 157 }; 147 158 148 159 #define EXYNOS4412_TMU_DATA \ ··· 142 227 .freq_clip_max = 400 * 1000, \ 143 228 .temp_level = 95, \ 144 229 }, \ 145 - .freq_tab_count = 2, \ 146 - .triminfo_reload[0] = EXYNOS_TRIMINFO_RELOAD_ENABLE, \ 147 - .registers = &exynos4412_tmu_registers, \ 148 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \ 149 - TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \ 150 - TMU_SUPPORT_EMUL_TIME) 151 - #endif 230 + .freq_tab_count = 2 152 231 153 - #if defined(CONFIG_SOC_EXYNOS4412) 154 232 struct exynos_tmu_init_data const exynos4412_default_tmu_data = { 155 233 .tmu_data = { 156 234 { 157 235 EXYNOS4412_TMU_DATA, 158 236 .type = SOC_ARCH_EXYNOS4412, 159 - .test_mux = EXYNOS4412_MUX_ADDR_VALUE, 160 237 }, 161 238 }, 162 239 .tmu_count = 1, 163 240 }; 164 - #endif 165 241 166 - #if defined(CONFIG_SOC_EXYNOS5250) 167 242 struct exynos_tmu_init_data const exynos5250_default_tmu_data = { 168 243 .tmu_data = { 169 244 { ··· 162 257 }, 163 258 }, 164 259 .tmu_count = 1, 165 - }; 166 - #endif 167 - 168 - #if defined(CONFIG_SOC_EXYNOS5260) 169 - static const struct exynos_tmu_registers exynos5260_tmu_registers = { 170 - .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 171 - .tmu_ctrl = EXYNOS_TMU_REG_CONTROL, 172 - .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT, 173 - .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK, 174 - .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT, 175 - .tmu_status = EXYNOS_TMU_REG_STATUS, 176 - .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP, 177 - .threshold_th0 = EXYNOS_THD_TEMP_RISE, 178 - .threshold_th1 = EXYNOS_THD_TEMP_FALL, 179 - .tmu_inten = EXYNOS5260_TMU_REG_INTEN, 180 - .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT, 181 - .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT, 182 - .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT, 183 - .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT, 184 - .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT, 185 - .tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT, 186 - .tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR, 187 - .emul_con = EXYNOS5260_EMUL_CON, 188 - .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT, 189 - .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT, 190 260 }; 191 261 192 262 #define __EXYNOS5260_TMU_DATA \ ··· 199 319 .temp_level = 103, \ 200 320 }, \ 201 321 .freq_tab_count = 2, \ 202 - .registers = &exynos5260_tmu_registers, \ 203 322 204 323 #define EXYNOS5260_TMU_DATA \ 205 324 __EXYNOS5260_TMU_DATA \ 206 - .type = SOC_ARCH_EXYNOS5260, \ 207 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \ 208 - TMU_SUPPORT_READY_STATUS | TMU_SUPPORT_EMUL_TIME) 325 + .type = SOC_ARCH_EXYNOS5260 209 326 210 327 struct exynos_tmu_init_data const exynos5260_default_tmu_data = { 211 328 .tmu_data = { ··· 214 337 }, 215 338 .tmu_count = 5, 216 339 }; 217 - #endif 218 - 219 - #if defined(CONFIG_SOC_EXYNOS5420) 220 - static const struct exynos_tmu_registers exynos5420_tmu_registers = { 221 - .triminfo_data = EXYNOS_TMU_REG_TRIMINFO, 222 - .tmu_ctrl = EXYNOS_TMU_REG_CONTROL, 223 - .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT, 224 - .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK, 225 - .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT, 226 - .tmu_status = EXYNOS_TMU_REG_STATUS, 227 - .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP, 228 - .threshold_th0 = EXYNOS_THD_TEMP_RISE, 229 - .threshold_th1 = EXYNOS_THD_TEMP_FALL, 230 - .tmu_inten = EXYNOS_TMU_REG_INTEN, 231 - .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT, 232 - .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT, 233 - .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT, 234 - /* INTEN_RISE3 Not availble in exynos5420 */ 235 - .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT, 236 - .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT, 237 - .tmu_intstat = EXYNOS_TMU_REG_INTSTAT, 238 - .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR, 239 - .emul_con = EXYNOS_EMUL_CON, 240 - .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT, 241 - .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT, 242 - }; 243 - 244 - #define __EXYNOS5420_TMU_DATA \ 245 - .threshold_falling = 10, \ 246 - .trigger_levels[0] = 85, \ 247 - .trigger_levels[1] = 103, \ 248 - .trigger_levels[2] = 110, \ 249 - .trigger_levels[3] = 120, \ 250 - .trigger_enable[0] = true, \ 251 - .trigger_enable[1] = true, \ 252 - .trigger_enable[2] = true, \ 253 - .trigger_enable[3] = false, \ 254 - .trigger_type[0] = THROTTLE_ACTIVE, \ 255 - .trigger_type[1] = THROTTLE_ACTIVE, \ 256 - .trigger_type[2] = SW_TRIP, \ 257 - .trigger_type[3] = HW_TRIP, \ 258 - .max_trigger_level = 4, \ 259 - .non_hw_trigger_levels = 3, \ 260 - .gain = 8, \ 261 - .reference_voltage = 16, \ 262 - .noise_cancel_mode = 4, \ 263 - .cal_type = TYPE_ONE_POINT_TRIMMING, \ 264 - .efuse_value = 55, \ 265 - .min_efuse_value = 40, \ 266 - .max_efuse_value = 100, \ 267 - .first_point_trim = 25, \ 268 - .second_point_trim = 85, \ 269 - .default_temp_offset = 50, \ 270 - .freq_tab[0] = { \ 271 - .freq_clip_max = 800 * 1000, \ 272 - .temp_level = 85, \ 273 - }, \ 274 - .freq_tab[1] = { \ 275 - .freq_clip_max = 200 * 1000, \ 276 - .temp_level = 103, \ 277 - }, \ 278 - .freq_tab_count = 2, \ 279 - .registers = &exynos5420_tmu_registers, \ 280 340 281 341 #define EXYNOS5420_TMU_DATA \ 282 - __EXYNOS5420_TMU_DATA \ 283 - .type = SOC_ARCH_EXYNOS5250, \ 284 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \ 285 - TMU_SUPPORT_READY_STATUS | TMU_SUPPORT_EMUL_TIME) 342 + __EXYNOS5260_TMU_DATA \ 343 + .type = SOC_ARCH_EXYNOS5420 286 344 287 345 #define EXYNOS5420_TMU_DATA_SHARED \ 288 - __EXYNOS5420_TMU_DATA \ 289 - .type = SOC_ARCH_EXYNOS5420_TRIMINFO, \ 290 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \ 291 - TMU_SUPPORT_READY_STATUS | TMU_SUPPORT_EMUL_TIME | \ 292 - TMU_SUPPORT_ADDRESS_MULTIPLE) 346 + __EXYNOS5260_TMU_DATA \ 347 + .type = SOC_ARCH_EXYNOS5420_TRIMINFO 293 348 294 349 struct exynos_tmu_init_data const exynos5420_default_tmu_data = { 295 350 .tmu_data = { ··· 232 423 { EXYNOS5420_TMU_DATA_SHARED }, 233 424 }, 234 425 .tmu_count = 5, 235 - }; 236 - #endif 237 - 238 - #if defined(CONFIG_SOC_EXYNOS5440) 239 - static const struct exynos_tmu_registers exynos5440_tmu_registers = { 240 - .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM, 241 - .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL, 242 - .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT, 243 - .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK, 244 - .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT, 245 - .tmu_status = EXYNOS5440_TMU_S0_7_STATUS, 246 - .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP, 247 - .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0, 248 - .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1, 249 - .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2, 250 - .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT, 251 - .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN, 252 - .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT, 253 - .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT, 254 - .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT, 255 - .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT, 256 - .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT, 257 - .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ, 258 - .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ, 259 - .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS, 260 - .emul_con = EXYNOS5440_TMU_S0_7_DEBUG, 261 - .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT, 262 - .tmu_pmin = EXYNOS5440_TMU_PMIN, 263 426 }; 264 427 265 428 #define EXYNOS5440_TMU_DATA \ ··· 252 471 .first_point_trim = 25, \ 253 472 .second_point_trim = 70, \ 254 473 .default_temp_offset = 25, \ 255 - .type = SOC_ARCH_EXYNOS5440, \ 256 - .registers = &exynos5440_tmu_registers, \ 257 - .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \ 258 - TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_ADDRESS_MULTIPLE), 474 + .type = SOC_ARCH_EXYNOS5440 259 475 260 476 struct exynos_tmu_init_data const exynos5440_default_tmu_data = { 261 477 .tmu_data = { ··· 262 484 }, 263 485 .tmu_count = 3, 264 486 }; 265 - #endif
-159
drivers/thermal/samsung/exynos_tmu_data.h
··· 1 - /* 2 - * exynos_tmu_data.h - Samsung EXYNOS tmu data header file 3 - * 4 - * Copyright (C) 2013 Samsung Electronics 5 - * Amit Daniel Kachhap <amit.daniel@samsung.com> 6 - * 7 - * This program is free software; you can redistribute it and/or modify 8 - * it under the terms of the GNU General Public License as published by 9 - * the Free Software Foundation; either version 2 of the License, or 10 - * (at your option) any later version. 11 - * 12 - * This program is distributed in the hope that it will be useful, 13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - * GNU General Public License for more details. 16 - * 17 - * You should have received a copy of the GNU General Public License 18 - * along with this program; if not, write to the Free Software 19 - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 - * 21 - */ 22 - 23 - #ifndef _EXYNOS_TMU_DATA_H 24 - #define _EXYNOS_TMU_DATA_H 25 - 26 - /* Exynos generic registers */ 27 - #define EXYNOS_TMU_REG_TRIMINFO 0x0 28 - #define EXYNOS_TMU_REG_CONTROL 0x20 29 - #define EXYNOS_TMU_REG_STATUS 0x28 30 - #define EXYNOS_TMU_REG_CURRENT_TEMP 0x40 31 - #define EXYNOS_TMU_REG_INTEN 0x70 32 - #define EXYNOS_TMU_REG_INTSTAT 0x74 33 - #define EXYNOS_TMU_REG_INTCLEAR 0x78 34 - 35 - #define EXYNOS_TMU_TEMP_MASK 0xff 36 - #define EXYNOS_TMU_REF_VOLTAGE_SHIFT 24 37 - #define EXYNOS_TMU_REF_VOLTAGE_MASK 0x1f 38 - #define EXYNOS_TMU_BUF_SLOPE_SEL_MASK 0xf 39 - #define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8 40 - #define EXYNOS_TMU_CORE_EN_SHIFT 0 41 - 42 - /* Exynos3250 specific registers */ 43 - #define EXYNOS_TMU_TRIMINFO_CON1 0x10 44 - 45 - /* Exynos4210 specific registers */ 46 - #define EXYNOS4210_TMU_REG_THRESHOLD_TEMP 0x44 47 - #define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50 48 - 49 - /* Exynos5250, Exynos4412, Exynos3250 specific registers */ 50 - #define EXYNOS_TMU_TRIMINFO_CON2 0x14 51 - #define EXYNOS_THD_TEMP_RISE 0x50 52 - #define EXYNOS_THD_TEMP_FALL 0x54 53 - #define EXYNOS_EMUL_CON 0x80 54 - 55 - #define EXYNOS_TRIMINFO_RELOAD_ENABLE 1 56 - #define EXYNOS_TRIMINFO_25_SHIFT 0 57 - #define EXYNOS_TRIMINFO_85_SHIFT 8 58 - #define EXYNOS_TMU_TRIP_MODE_SHIFT 13 59 - #define EXYNOS_TMU_TRIP_MODE_MASK 0x7 60 - #define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12 61 - 62 - #define EXYNOS_TMU_INTEN_RISE0_SHIFT 0 63 - #define EXYNOS_TMU_INTEN_RISE1_SHIFT 4 64 - #define EXYNOS_TMU_INTEN_RISE2_SHIFT 8 65 - #define EXYNOS_TMU_INTEN_RISE3_SHIFT 12 66 - #define EXYNOS_TMU_INTEN_FALL0_SHIFT 16 67 - 68 - #define EXYNOS_EMUL_TIME 0x57F0 69 - #define EXYNOS_EMUL_TIME_MASK 0xffff 70 - #define EXYNOS_EMUL_TIME_SHIFT 16 71 - #define EXYNOS_EMUL_DATA_SHIFT 8 72 - #define EXYNOS_EMUL_DATA_MASK 0xFF 73 - #define EXYNOS_EMUL_ENABLE 0x1 74 - 75 - #define EXYNOS_MAX_TRIGGER_PER_REG 4 76 - 77 - /* Exynos5260 specific */ 78 - #define EXYNOS5260_TMU_REG_INTEN 0xC0 79 - #define EXYNOS5260_TMU_REG_INTSTAT 0xC4 80 - #define EXYNOS5260_TMU_REG_INTCLEAR 0xC8 81 - #define EXYNOS5260_EMUL_CON 0x100 82 - 83 - /* Exynos4412 specific */ 84 - #define EXYNOS4412_MUX_ADDR_VALUE 6 85 - #define EXYNOS4412_MUX_ADDR_SHIFT 20 86 - 87 - /*exynos5440 specific registers*/ 88 - #define EXYNOS5440_TMU_S0_7_TRIM 0x000 89 - #define EXYNOS5440_TMU_S0_7_CTRL 0x020 90 - #define EXYNOS5440_TMU_S0_7_DEBUG 0x040 91 - #define EXYNOS5440_TMU_S0_7_STATUS 0x060 92 - #define EXYNOS5440_TMU_S0_7_TEMP 0x0f0 93 - #define EXYNOS5440_TMU_S0_7_TH0 0x110 94 - #define EXYNOS5440_TMU_S0_7_TH1 0x130 95 - #define EXYNOS5440_TMU_S0_7_TH2 0x150 96 - #define EXYNOS5440_TMU_S0_7_IRQEN 0x210 97 - #define EXYNOS5440_TMU_S0_7_IRQ 0x230 98 - /* exynos5440 common registers */ 99 - #define EXYNOS5440_TMU_IRQ_STATUS 0x000 100 - #define EXYNOS5440_TMU_PMIN 0x004 101 - 102 - #define EXYNOS5440_TMU_INTEN_RISE0_SHIFT 0 103 - #define EXYNOS5440_TMU_INTEN_RISE1_SHIFT 1 104 - #define EXYNOS5440_TMU_INTEN_RISE2_SHIFT 2 105 - #define EXYNOS5440_TMU_INTEN_RISE3_SHIFT 3 106 - #define EXYNOS5440_TMU_INTEN_FALL0_SHIFT 4 107 - #define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 108 - #define EXYNOS5440_EFUSE_SWAP_OFFSET 8 109 - 110 - #if defined(CONFIG_SOC_EXYNOS3250) 111 - extern struct exynos_tmu_init_data const exynos3250_default_tmu_data; 112 - #define EXYNOS3250_TMU_DRV_DATA (&exynos3250_default_tmu_data) 113 - #else 114 - #define EXYNOS3250_TMU_DRV_DATA (NULL) 115 - #endif 116 - 117 - #if defined(CONFIG_CPU_EXYNOS4210) 118 - extern struct exynos_tmu_init_data const exynos4210_default_tmu_data; 119 - #define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data) 120 - #else 121 - #define EXYNOS4210_TMU_DRV_DATA (NULL) 122 - #endif 123 - 124 - #if defined(CONFIG_SOC_EXYNOS4412) 125 - extern struct exynos_tmu_init_data const exynos4412_default_tmu_data; 126 - #define EXYNOS4412_TMU_DRV_DATA (&exynos4412_default_tmu_data) 127 - #else 128 - #define EXYNOS4412_TMU_DRV_DATA (NULL) 129 - #endif 130 - 131 - #if defined(CONFIG_SOC_EXYNOS5250) 132 - extern struct exynos_tmu_init_data const exynos5250_default_tmu_data; 133 - #define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data) 134 - #else 135 - #define EXYNOS5250_TMU_DRV_DATA (NULL) 136 - #endif 137 - 138 - #if defined(CONFIG_SOC_EXYNOS5260) 139 - extern struct exynos_tmu_init_data const exynos5260_default_tmu_data; 140 - #define EXYNOS5260_TMU_DRV_DATA (&exynos5260_default_tmu_data) 141 - #else 142 - #define EXYNOS5260_TMU_DRV_DATA (NULL) 143 - #endif 144 - 145 - #if defined(CONFIG_SOC_EXYNOS5420) 146 - extern struct exynos_tmu_init_data const exynos5420_default_tmu_data; 147 - #define EXYNOS5420_TMU_DRV_DATA (&exynos5420_default_tmu_data) 148 - #else 149 - #define EXYNOS5420_TMU_DRV_DATA (NULL) 150 - #endif 151 - 152 - #if defined(CONFIG_SOC_EXYNOS5440) 153 - extern struct exynos_tmu_init_data const exynos5440_default_tmu_data; 154 - #define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data) 155 - #else 156 - #define EXYNOS5440_TMU_DRV_DATA (NULL) 157 - #endif 158 - 159 - #endif /*_EXYNOS_TMU_DATA_H*/
+476
drivers/thermal/tegra_soctherm.c
··· 1 + /* 2 + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * Author: 5 + * Mikko Perttunen <mperttunen@nvidia.com> 6 + * 7 + * This software is licensed under the terms of the GNU General Public 8 + * License version 2, as published by the Free Software Foundation, and 9 + * may be copied, distributed, and modified under those terms. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + */ 17 + 18 + #include <linux/bitops.h> 19 + #include <linux/clk.h> 20 + #include <linux/delay.h> 21 + #include <linux/err.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/io.h> 24 + #include <linux/module.h> 25 + #include <linux/of.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/reset.h> 28 + #include <linux/thermal.h> 29 + 30 + #include <soc/tegra/fuse.h> 31 + 32 + #define SENSOR_CONFIG0 0 33 + #define SENSOR_CONFIG0_STOP BIT(0) 34 + #define SENSOR_CONFIG0_TALL_SHIFT 8 35 + #define SENSOR_CONFIG0_TCALC_OVER BIT(4) 36 + #define SENSOR_CONFIG0_OVER BIT(3) 37 + #define SENSOR_CONFIG0_CPTR_OVER BIT(2) 38 + 39 + #define SENSOR_CONFIG1 4 40 + #define SENSOR_CONFIG1_TSAMPLE_SHIFT 0 41 + #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 15 42 + #define SENSOR_CONFIG1_TEN_COUNT_SHIFT 24 43 + #define SENSOR_CONFIG1_TEMP_ENABLE BIT(31) 44 + 45 + #define SENSOR_CONFIG2 8 46 + #define SENSOR_CONFIG2_THERMA_SHIFT 16 47 + #define SENSOR_CONFIG2_THERMB_SHIFT 0 48 + 49 + #define SENSOR_PDIV 0x1c0 50 + #define SENSOR_PDIV_T124 0x8888 51 + #define SENSOR_HOTSPOT_OFF 0x1c4 52 + #define SENSOR_HOTSPOT_OFF_T124 0x00060600 53 + #define SENSOR_TEMP1 0x1c8 54 + #define SENSOR_TEMP2 0x1cc 55 + 56 + #define SENSOR_TEMP_MASK 0xffff 57 + #define READBACK_VALUE_MASK 0xff00 58 + #define READBACK_VALUE_SHIFT 8 59 + #define READBACK_ADD_HALF BIT(7) 60 + #define READBACK_NEGATE BIT(1) 61 + 62 + #define FUSE_TSENSOR8_CALIB 0x180 63 + #define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc 64 + 65 + #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK 0x1fff 66 + #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK (0x1fff << 13) 67 + #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13 68 + 69 + #define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK 0x3ff 70 + #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK (0x7ff << 10) 71 + #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT 10 72 + 73 + #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f 74 + #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21) 75 + #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21 76 + 77 + #define NOMINAL_CALIB_FT_T124 105 78 + #define NOMINAL_CALIB_CP_T124 25 79 + 80 + struct tegra_tsensor_configuration { 81 + u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate; 82 + }; 83 + 84 + struct tegra_tsensor { 85 + const struct tegra_tsensor_configuration *config; 86 + u32 base, calib_fuse_offset; 87 + /* Correction values used to modify values read from calibration fuses */ 88 + s32 fuse_corr_alpha, fuse_corr_beta; 89 + }; 90 + 91 + struct tegra_thermctl_zone { 92 + void __iomem *reg; 93 + unsigned int shift; 94 + }; 95 + 96 + static const struct tegra_tsensor_configuration t124_tsensor_config = { 97 + .tall = 16300, 98 + .tsample = 120, 99 + .tiddq_en = 1, 100 + .ten_count = 1, 101 + .pdiv = 8, 102 + .tsample_ate = 480, 103 + .pdiv_ate = 8 104 + }; 105 + 106 + static const struct tegra_tsensor t124_tsensors[] = { 107 + { 108 + .config = &t124_tsensor_config, 109 + .base = 0xc0, 110 + .calib_fuse_offset = 0x098, 111 + .fuse_corr_alpha = 1135400, 112 + .fuse_corr_beta = -6266900, 113 + }, 114 + { 115 + .config = &t124_tsensor_config, 116 + .base = 0xe0, 117 + .calib_fuse_offset = 0x084, 118 + .fuse_corr_alpha = 1122220, 119 + .fuse_corr_beta = -5700700, 120 + }, 121 + { 122 + .config = &t124_tsensor_config, 123 + .base = 0x100, 124 + .calib_fuse_offset = 0x088, 125 + .fuse_corr_alpha = 1127000, 126 + .fuse_corr_beta = -6768200, 127 + }, 128 + { 129 + .config = &t124_tsensor_config, 130 + .base = 0x120, 131 + .calib_fuse_offset = 0x12c, 132 + .fuse_corr_alpha = 1110900, 133 + .fuse_corr_beta = -6232000, 134 + }, 135 + { 136 + .config = &t124_tsensor_config, 137 + .base = 0x140, 138 + .calib_fuse_offset = 0x158, 139 + .fuse_corr_alpha = 1122300, 140 + .fuse_corr_beta = -5936400, 141 + }, 142 + { 143 + .config = &t124_tsensor_config, 144 + .base = 0x160, 145 + .calib_fuse_offset = 0x15c, 146 + .fuse_corr_alpha = 1145700, 147 + .fuse_corr_beta = -7124600, 148 + }, 149 + { 150 + .config = &t124_tsensor_config, 151 + .base = 0x180, 152 + .calib_fuse_offset = 0x154, 153 + .fuse_corr_alpha = 1120100, 154 + .fuse_corr_beta = -6000500, 155 + }, 156 + { 157 + .config = &t124_tsensor_config, 158 + .base = 0x1a0, 159 + .calib_fuse_offset = 0x160, 160 + .fuse_corr_alpha = 1106500, 161 + .fuse_corr_beta = -6729300, 162 + }, 163 + }; 164 + 165 + struct tegra_soctherm { 166 + struct reset_control *reset; 167 + struct clk *clock_tsensor; 168 + struct clk *clock_soctherm; 169 + void __iomem *regs; 170 + 171 + struct thermal_zone_device *thermctl_tzs[4]; 172 + }; 173 + 174 + struct tsensor_shared_calibration { 175 + u32 base_cp, base_ft; 176 + u32 actual_temp_cp, actual_temp_ft; 177 + }; 178 + 179 + static int calculate_shared_calibration(struct tsensor_shared_calibration *r) 180 + { 181 + u32 val, shifted_cp, shifted_ft; 182 + int err; 183 + 184 + err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val); 185 + if (err) 186 + return err; 187 + r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK; 188 + r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK) 189 + >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT; 190 + val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK) 191 + >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT); 192 + shifted_ft = sign_extend32(val, 4); 193 + 194 + err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val); 195 + if (err) 196 + return err; 197 + shifted_cp = sign_extend32(val, 5); 198 + 199 + r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp; 200 + r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft; 201 + 202 + return 0; 203 + } 204 + 205 + static s64 div64_s64_precise(s64 a, s64 b) 206 + { 207 + s64 r, al; 208 + 209 + /* Scale up for increased precision division */ 210 + al = a << 16; 211 + 212 + r = div64_s64(al * 2 + 1, 2 * b); 213 + return r >> 16; 214 + } 215 + 216 + static int 217 + calculate_tsensor_calibration(const struct tegra_tsensor *sensor, 218 + const struct tsensor_shared_calibration *shared, 219 + u32 *calib) 220 + { 221 + u32 val; 222 + s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp, 223 + mult, div; 224 + s16 therma, thermb; 225 + s64 tmp; 226 + int err; 227 + 228 + err = tegra_fuse_readl(sensor->calib_fuse_offset, &val); 229 + if (err) 230 + return err; 231 + 232 + actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12); 233 + val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK) 234 + >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT; 235 + actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12); 236 + 237 + delta_sens = actual_tsensor_ft - actual_tsensor_cp; 238 + delta_temp = shared->actual_temp_ft - shared->actual_temp_cp; 239 + 240 + mult = sensor->config->pdiv * sensor->config->tsample_ate; 241 + div = sensor->config->tsample * sensor->config->pdiv_ate; 242 + 243 + therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult, 244 + (s64) delta_sens * div); 245 + 246 + tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp - 247 + (s64)actual_tsensor_cp * shared->actual_temp_ft; 248 + thermb = div64_s64_precise(tmp, (s64)delta_sens); 249 + 250 + therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha, 251 + (s64)1000000LL); 252 + thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha + 253 + sensor->fuse_corr_beta, (s64)1000000LL); 254 + 255 + *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) | 256 + ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT); 257 + 258 + return 0; 259 + } 260 + 261 + static int enable_tsensor(struct tegra_soctherm *tegra, 262 + const struct tegra_tsensor *sensor, 263 + const struct tsensor_shared_calibration *shared) 264 + { 265 + void __iomem *base = tegra->regs + sensor->base; 266 + unsigned int val; 267 + u32 calib; 268 + int err; 269 + 270 + err = calculate_tsensor_calibration(sensor, shared, &calib); 271 + if (err) 272 + return err; 273 + 274 + val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT; 275 + writel(val, base + SENSOR_CONFIG0); 276 + 277 + val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT; 278 + val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT; 279 + val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT; 280 + val |= SENSOR_CONFIG1_TEMP_ENABLE; 281 + writel(val, base + SENSOR_CONFIG1); 282 + 283 + writel(calib, base + SENSOR_CONFIG2); 284 + 285 + return 0; 286 + } 287 + 288 + /* 289 + * Translate from soctherm readback format to millicelsius. 290 + * The soctherm readback format in bits is as follows: 291 + * TTTTTTTT H______N 292 + * where T's contain the temperature in Celsius, 293 + * H denotes an addition of 0.5 Celsius and N denotes negation 294 + * of the final value. 295 + */ 296 + static long translate_temp(u16 val) 297 + { 298 + long t; 299 + 300 + t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000; 301 + if (val & READBACK_ADD_HALF) 302 + t += 500; 303 + if (val & READBACK_NEGATE) 304 + t *= -1; 305 + 306 + return t; 307 + } 308 + 309 + static int tegra_thermctl_get_temp(void *data, long *out_temp) 310 + { 311 + struct tegra_thermctl_zone *zone = data; 312 + u32 val; 313 + 314 + val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK; 315 + *out_temp = translate_temp(val); 316 + 317 + return 0; 318 + } 319 + 320 + static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { 321 + .get_temp = tegra_thermctl_get_temp, 322 + }; 323 + 324 + static const struct of_device_id tegra_soctherm_of_match[] = { 325 + { .compatible = "nvidia,tegra124-soctherm" }, 326 + { }, 327 + }; 328 + MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match); 329 + 330 + struct thermctl_zone_desc { 331 + unsigned int offset; 332 + unsigned int shift; 333 + }; 334 + 335 + static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = { 336 + { SENSOR_TEMP1, 16 }, 337 + { SENSOR_TEMP2, 16 }, 338 + { SENSOR_TEMP1, 0 }, 339 + { SENSOR_TEMP2, 0 } 340 + }; 341 + 342 + static int tegra_soctherm_probe(struct platform_device *pdev) 343 + { 344 + struct tegra_soctherm *tegra; 345 + struct thermal_zone_device *tz; 346 + struct tsensor_shared_calibration shared_calib; 347 + struct resource *res; 348 + unsigned int i; 349 + int err; 350 + 351 + const struct tegra_tsensor *tsensors = t124_tsensors; 352 + 353 + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); 354 + if (!tegra) 355 + return -ENOMEM; 356 + 357 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 358 + tegra->regs = devm_ioremap_resource(&pdev->dev, res); 359 + if (IS_ERR(tegra->regs)) 360 + return PTR_ERR(tegra->regs); 361 + 362 + tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); 363 + if (IS_ERR(tegra->reset)) { 364 + dev_err(&pdev->dev, "can't get soctherm reset\n"); 365 + return PTR_ERR(tegra->reset); 366 + } 367 + 368 + tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor"); 369 + if (IS_ERR(tegra->clock_tsensor)) { 370 + dev_err(&pdev->dev, "can't get tsensor clock\n"); 371 + return PTR_ERR(tegra->clock_tsensor); 372 + } 373 + 374 + tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm"); 375 + if (IS_ERR(tegra->clock_soctherm)) { 376 + dev_err(&pdev->dev, "can't get soctherm clock\n"); 377 + return PTR_ERR(tegra->clock_soctherm); 378 + } 379 + 380 + reset_control_assert(tegra->reset); 381 + 382 + err = clk_prepare_enable(tegra->clock_soctherm); 383 + if (err) 384 + return err; 385 + 386 + err = clk_prepare_enable(tegra->clock_tsensor); 387 + if (err) { 388 + clk_disable_unprepare(tegra->clock_soctherm); 389 + return err; 390 + } 391 + 392 + reset_control_deassert(tegra->reset); 393 + 394 + /* Initialize raw sensors */ 395 + 396 + err = calculate_shared_calibration(&shared_calib); 397 + if (err) 398 + goto disable_clocks; 399 + 400 + for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) { 401 + err = enable_tsensor(tegra, tsensors + i, &shared_calib); 402 + if (err) 403 + goto disable_clocks; 404 + } 405 + 406 + writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV); 407 + writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF); 408 + 409 + /* Initialize thermctl sensors */ 410 + 411 + for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { 412 + struct tegra_thermctl_zone *zone = 413 + devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL); 414 + if (!zone) { 415 + err = -ENOMEM; 416 + goto unregister_tzs; 417 + } 418 + 419 + zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset; 420 + zone->shift = t124_thermctl_temp_zones[i].shift; 421 + 422 + tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone, 423 + &tegra_of_thermal_ops); 424 + if (IS_ERR(tz)) { 425 + err = PTR_ERR(tz); 426 + dev_err(&pdev->dev, "failed to register sensor: %d\n", 427 + err); 428 + goto unregister_tzs; 429 + } 430 + 431 + tegra->thermctl_tzs[i] = tz; 432 + } 433 + 434 + return 0; 435 + 436 + unregister_tzs: 437 + while (i--) 438 + thermal_zone_of_sensor_unregister(&pdev->dev, 439 + tegra->thermctl_tzs[i]); 440 + 441 + disable_clocks: 442 + clk_disable_unprepare(tegra->clock_tsensor); 443 + clk_disable_unprepare(tegra->clock_soctherm); 444 + 445 + return err; 446 + } 447 + 448 + static int tegra_soctherm_remove(struct platform_device *pdev) 449 + { 450 + struct tegra_soctherm *tegra = platform_get_drvdata(pdev); 451 + unsigned int i; 452 + 453 + for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) { 454 + thermal_zone_of_sensor_unregister(&pdev->dev, 455 + tegra->thermctl_tzs[i]); 456 + } 457 + 458 + clk_disable_unprepare(tegra->clock_tsensor); 459 + clk_disable_unprepare(tegra->clock_soctherm); 460 + 461 + return 0; 462 + } 463 + 464 + static struct platform_driver tegra_soctherm_driver = { 465 + .probe = tegra_soctherm_probe, 466 + .remove = tegra_soctherm_remove, 467 + .driver = { 468 + .name = "tegra-soctherm", 469 + .of_match_table = tegra_soctherm_of_match, 470 + }, 471 + }; 472 + module_platform_driver(tegra_soctherm_driver); 473 + 474 + MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); 475 + MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver"); 476 + MODULE_LICENSE("GPL v2");
+5 -3
drivers/thermal/thermal_core.c
··· 368 368 tz->ops->get_trip_temp(tz, trip, &trip_temp); 369 369 370 370 /* If we have not crossed the trip_temp, we do not care. */ 371 - if (tz->temperature < trip_temp) 371 + if (trip_temp <= 0 || tz->temperature < trip_temp) 372 372 return; 373 373 374 374 trace_thermal_zone_trip(tz, trip, trip_type); ··· 757 757 snprintf(name, sizeof(name), "%s", buf); 758 758 759 759 mutex_lock(&thermal_governor_lock); 760 + mutex_lock(&tz->lock); 760 761 761 762 gov = __find_governor(strim(name)); 762 763 if (!gov) ··· 767 766 ret = count; 768 767 769 768 exit: 769 + mutex_unlock(&tz->lock); 770 770 mutex_unlock(&thermal_governor_lock); 771 771 return ret; 772 772 } ··· 1837 1835 1838 1836 exit_netlink: 1839 1837 genetlink_exit(); 1840 - unregister_governors: 1841 - thermal_unregister_governors(); 1842 1838 unregister_class: 1843 1839 class_unregister(&thermal_class); 1840 + unregister_governors: 1841 + thermal_unregister_governors(); 1844 1842 error: 1845 1843 idr_destroy(&thermal_tz_idr); 1846 1844 idr_destroy(&thermal_cdev_idr);
+18
drivers/thermal/thermal_core.h
··· 89 89 #ifdef CONFIG_THERMAL_OF 90 90 int of_parse_thermal_zones(void); 91 91 void of_thermal_destroy_zones(void); 92 + int of_thermal_get_ntrips(struct thermal_zone_device *); 93 + bool of_thermal_is_trip_valid(struct thermal_zone_device *, int); 94 + const struct thermal_trip * const 95 + of_thermal_get_trip_points(struct thermal_zone_device *); 92 96 #else 93 97 static inline int of_parse_thermal_zones(void) { return 0; } 94 98 static inline void of_thermal_destroy_zones(void) { } 99 + static inline int of_thermal_get_ntrips(struct thermal_zone_device *tz) 100 + { 101 + return 0; 102 + } 103 + static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, 104 + int trip) 105 + { 106 + return 0; 107 + } 108 + static inline const struct thermal_trip * const 109 + of_thermal_get_trip_points(struct thermal_zone_device *tz) 110 + { 111 + return NULL; 112 + } 95 113 #endif 96 114 97 115 #endif /* __THERMAL_CORE_H__ */
+6 -2
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
··· 286 286 return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp); 287 287 } 288 288 289 + static const struct thermal_zone_of_device_ops ti_of_thermal_ops = { 290 + .get_temp = __ti_thermal_get_temp, 291 + .get_trend = __ti_thermal_get_trend, 292 + }; 293 + 289 294 static struct thermal_zone_device_ops ti_thermal_ops = { 290 295 .get_temp = ti_thermal_get_temp, 291 296 .get_trend = ti_thermal_get_trend, ··· 338 333 339 334 /* in case this is specified by DT */ 340 335 data->ti_thermal = thermal_zone_of_sensor_register(bgp->dev, id, 341 - data, __ti_thermal_get_temp, 342 - __ti_thermal_get_trend); 336 + data, &ti_of_thermal_ops); 343 337 if (IS_ERR(data->ti_thermal)) { 344 338 /* Create thermal zone */ 345 339 data->ti_thermal = thermal_zone_device_register(domain,
+13
include/dt-bindings/thermal/tegra124-soctherm.h
··· 1 + /* 2 + * This header provides constants for binding nvidia,tegra124-soctherm. 3 + */ 4 + 5 + #ifndef _DT_BINDINGS_THERMAL_TEGRA124_SOCTHERM_H 6 + #define _DT_BINDINGS_THERMAL_TEGRA124_SOCTHERM_H 7 + 8 + #define TEGRA124_SOCTHERM_SENSOR_CPU 0 9 + #define TEGRA124_SOCTHERM_SENSOR_MEM 1 10 + #define TEGRA124_SOCTHERM_SENSOR_GPU 2 11 + #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 12 + 13 + #endif
+65
include/linux/clock_cooling.h
··· 1 + /* 2 + * linux/include/linux/clock_cooling.h 3 + * 4 + * Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com> 5 + * 6 + * Copyright (C) 2013 Texas Instruments Inc. 7 + * Contact: Eduardo Valentin <eduardo.valentin@ti.com> 8 + * 9 + * Highly based on cpu_cooling.c. 10 + * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) 11 + * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> 12 + * 13 + * This program is free software; you can redistribute it and/or modify 14 + * it under the terms of the GNU General Public License as published by 15 + * the Free Software Foundation; version 2 of the License. 16 + * 17 + * This program is distributed in the hope that it will be useful, but 18 + * WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 + * General Public License for more details. 21 + */ 22 + 23 + #ifndef __CPU_COOLING_H__ 24 + #define __CPU_COOLING_H__ 25 + 26 + #include <linux/of.h> 27 + #include <linux/thermal.h> 28 + #include <linux/cpumask.h> 29 + 30 + #ifdef CONFIG_CLOCK_THERMAL 31 + /** 32 + * clock_cooling_register - function to create clock cooling device. 33 + * @dev: struct device pointer to the device used as clock cooling device. 34 + * @clock_name: string containing the clock used as cooling mechanism. 35 + */ 36 + struct thermal_cooling_device * 37 + clock_cooling_register(struct device *dev, const char *clock_name); 38 + 39 + /** 40 + * clock_cooling_unregister - function to remove clock cooling device. 41 + * @cdev: thermal cooling device pointer. 42 + */ 43 + void clock_cooling_unregister(struct thermal_cooling_device *cdev); 44 + 45 + unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, 46 + unsigned long freq); 47 + #else /* !CONFIG_CLOCK_THERMAL */ 48 + static inline struct thermal_cooling_device * 49 + clock_cooling_register(struct device *dev, const char *clock_name) 50 + { 51 + return NULL; 52 + } 53 + static inline 54 + void clock_cooling_unregister(struct thermal_cooling_device *cdev) 55 + { 56 + } 57 + static inline 58 + unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev, 59 + unsigned long freq) 60 + { 61 + return THERMAL_CSTATE_INVALID; 62 + } 63 + #endif /* CONFIG_CLOCK_THERMAL */ 64 + 65 + #endif /* __CPU_COOLING_H__ */
+37 -36
include/linux/thermal.h
··· 29 29 #include <linux/idr.h> 30 30 #include <linux/device.h> 31 31 #include <linux/workqueue.h> 32 + #include <uapi/linux/thermal.h> 32 33 33 34 #define THERMAL_TRIPS_NONE -1 34 35 #define THERMAL_MAX_TRIPS 12 35 - #define THERMAL_NAME_LENGTH 20 36 36 37 37 /* invalid cooling state */ 38 38 #define THERMAL_CSTATE_INVALID -1UL ··· 48 48 #define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732) 49 49 #define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off)) 50 50 #define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732) 51 - 52 - /* Adding event notification support elements */ 53 - #define THERMAL_GENL_FAMILY_NAME "thermal_event" 54 - #define THERMAL_GENL_VERSION 0x01 55 - #define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" 56 51 57 52 /* Default Thermal Governor */ 58 53 #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) ··· 80 85 THERMAL_TREND_RAISE_FULL, /* apply highest cooling action */ 81 86 THERMAL_TREND_DROP_FULL, /* apply lowest cooling action */ 82 87 }; 83 - 84 - /* Events supported by Thermal Netlink */ 85 - enum events { 86 - THERMAL_AUX0, 87 - THERMAL_AUX1, 88 - THERMAL_CRITICAL, 89 - THERMAL_DEV_FAULT, 90 - }; 91 - 92 - /* attributes of thermal_genl_family */ 93 - enum { 94 - THERMAL_GENL_ATTR_UNSPEC, 95 - THERMAL_GENL_ATTR_EVENT, 96 - __THERMAL_GENL_ATTR_MAX, 97 - }; 98 - #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) 99 - 100 - /* commands supported by the thermal_genl_family */ 101 - enum { 102 - THERMAL_GENL_CMD_UNSPEC, 103 - THERMAL_GENL_CMD_EVENT, 104 - __THERMAL_GENL_CMD_MAX, 105 - }; 106 - #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) 107 88 108 89 struct thermal_zone_device_ops { 109 90 int (*bind) (struct thermal_zone_device *, ··· 260 289 enum events event; 261 290 }; 262 291 292 + /** 293 + * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones 294 + * 295 + * Mandatory: 296 + * @get_temp: a pointer to a function that reads the sensor temperature. 297 + * 298 + * Optional: 299 + * @get_trend: a pointer to a function that reads the sensor temperature trend. 300 + * @set_emul_temp: a pointer to a function that sets sensor emulated 301 + * temperature. 302 + */ 303 + struct thermal_zone_of_device_ops { 304 + int (*get_temp)(void *, long *); 305 + int (*get_trend)(void *, long *); 306 + int (*set_emul_temp)(void *, unsigned long); 307 + }; 308 + 309 + /** 310 + * struct thermal_trip - representation of a point in temperature domain 311 + * @np: pointer to struct device_node that this trip point was created from 312 + * @temperature: temperature value in miliCelsius 313 + * @hysteresis: relative hysteresis in miliCelsius 314 + * @type: trip point type 315 + */ 316 + 317 + struct thermal_trip { 318 + struct device_node *np; 319 + unsigned long int temperature; 320 + unsigned long int hysteresis; 321 + enum thermal_trip_type type; 322 + }; 323 + 263 324 /* Function declarations */ 264 325 #ifdef CONFIG_THERMAL_OF 265 326 struct thermal_zone_device * 266 - thermal_zone_of_sensor_register(struct device *dev, int id, 267 - void *data, int (*get_temp)(void *, long *), 268 - int (*get_trend)(void *, long *)); 327 + thermal_zone_of_sensor_register(struct device *dev, int id, void *data, 328 + const struct thermal_zone_of_device_ops *ops); 269 329 void thermal_zone_of_sensor_unregister(struct device *dev, 270 330 struct thermal_zone_device *tz); 271 331 #else 272 332 static inline struct thermal_zone_device * 273 - thermal_zone_of_sensor_register(struct device *dev, int id, 274 - void *data, int (*get_temp)(void *, long *), 275 - int (*get_trend)(void *, long *)) 333 + thermal_zone_of_sensor_register(struct device *dev, int id, void *data, 334 + const struct thermal_zone_of_device_ops *ops) 276 335 { 277 336 return NULL; 278 337 }
+1
include/uapi/linux/Kbuild
··· 387 387 header-y += tcp_metrics.h 388 388 header-y += telephony.h 389 389 header-y += termios.h 390 + header-y += thermal.h 390 391 header-y += time.h 391 392 header-y += times.h 392 393 header-y += timex.h
+35
include/uapi/linux/thermal.h
··· 1 + #ifndef _UAPI_LINUX_THERMAL_H 2 + #define _UAPI_LINUX_THERMAL_H 3 + 4 + #define THERMAL_NAME_LENGTH 20 5 + 6 + /* Adding event notification support elements */ 7 + #define THERMAL_GENL_FAMILY_NAME "thermal_event" 8 + #define THERMAL_GENL_VERSION 0x01 9 + #define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" 10 + 11 + /* Events supported by Thermal Netlink */ 12 + enum events { 13 + THERMAL_AUX0, 14 + THERMAL_AUX1, 15 + THERMAL_CRITICAL, 16 + THERMAL_DEV_FAULT, 17 + }; 18 + 19 + /* attributes of thermal_genl_family */ 20 + enum { 21 + THERMAL_GENL_ATTR_UNSPEC, 22 + THERMAL_GENL_ATTR_EVENT, 23 + __THERMAL_GENL_ATTR_MAX, 24 + }; 25 + #define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) 26 + 27 + /* commands supported by the thermal_genl_family */ 28 + enum { 29 + THERMAL_GENL_CMD_UNSPEC, 30 + THERMAL_GENL_CMD_EVENT, 31 + __THERMAL_GENL_CMD_MAX, 32 + }; 33 + #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) 34 + 35 + #endif /* _UAPI_LINUX_THERMAL_H */