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

Merge branches 'exynos-fix', 'for-rc', 'int3403-fix', 'misc', 'rcar-thermal' and 'sti-thermal' of .git into next

Zhang Rui 47d104ba 1fe56dc1

+986 -17
+12 -6
Documentation/devicetree/bindings/thermal/rcar-thermal.txt
··· 1 1 * Renesas R-Car Thermal 2 2 3 3 Required properties: 4 - - compatible : "renesas,rcar-thermal" 4 + - compatible : "renesas,thermal-<soctype>", "renesas,rcar-thermal" 5 + as fallback. 6 + Examples with soctypes are: 7 + - "renesas,thermal-r8a73a4" (R-Mobile AP6) 8 + - "renesas,thermal-r8a7779" (R-Car H1) 9 + - "renesas,thermal-r8a7790" (R-Car H2) 10 + - "renesas,thermal-r8a7791" (R-Car M2) 5 11 - reg : Address range of the thermal registers. 6 12 The 1st reg will be recognized as common register 7 13 if it has "interrupts". ··· 18 12 19 13 Example (non interrupt support): 20 14 21 - thermal@e61f0100 { 22 - compatible = "renesas,rcar-thermal"; 23 - reg = <0xe61f0100 0x38>; 15 + thermal@ffc48000 { 16 + compatible = "renesas,thermal-r8a7779", "renesas,rcar-thermal"; 17 + reg = <0xffc48000 0x38>; 24 18 }; 25 19 26 20 Example (interrupt support): 27 21 28 22 thermal@e61f0000 { 29 - compatible = "renesas,rcar-thermal"; 23 + compatible = "renesas,thermal-r8a73a4", "renesas,rcar-thermal"; 30 24 reg = <0xe61f0000 0x14 31 25 0xe61f0100 0x38 32 26 0xe61f0200 0x38 33 27 0xe61f0300 0x38>; 34 - interrupts = <0 69 4>; 28 + interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; 35 29 };
+42
Documentation/devicetree/bindings/thermal/st-thermal.txt
··· 1 + Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs. 2 + 3 + Required parameters: 4 + ------------------- 5 + 6 + compatible : st,<SoC>-<module>-thermal; should be one of: 7 + "st,stih415-sas-thermal", 8 + "st,stih415-mpe-thermal", 9 + "st,stih416-sas-thermal" 10 + "st,stih416-mpe-thermal" 11 + "st,stid127-thermal" or 12 + "st,stih407-thermal" 13 + according to the SoC type (stih415, stih416, stid127, stih407) 14 + and module type (sas or mpe). On stid127 & stih407 there is only 15 + one die/module, so there is no module type in the compatible 16 + string. 17 + clock-names : Should be "thermal". 18 + See: Documentation/devicetree/bindings/resource-names.txt 19 + clocks : Phandle of the clock used by the thermal sensor. 20 + See: Documentation/devicetree/bindings/clock/clock-bindings.txt 21 + 22 + Optional parameters: 23 + ------------------- 24 + 25 + reg : For non-sysconf based sensors, this should be the physical base 26 + address and length of the sensor's registers. 27 + interrupts : Standard way to define interrupt number. 28 + Interrupt is mandatory to be defined when compatible is 29 + "stih416-mpe-thermal". 30 + NB: For thermal sensor's for which no interrupt has been 31 + defined, a polling delay of 1000ms will be used to read the 32 + temperature from device. 33 + 34 + Example: 35 + 36 + temp1@fdfe8000 { 37 + compatible = "st,stih416-mpe-thermal"; 38 + reg = <0xfdfe8000 0x10>; 39 + clock-names = "thermal"; 40 + clocks = <&clk_m_mpethsens>; 41 + interrupts = <GIC_SPI 23 IRQ_TYPE_NONE>; 42 + };
+6 -1
drivers/thermal/Kconfig
··· 151 151 152 152 config DOVE_THERMAL 153 153 tristate "Temperature sensor on Marvell Dove SoCs" 154 - depends on ARCH_DOVE 154 + depends on ARCH_DOVE || MACH_DOVE 155 155 depends on OF 156 156 help 157 157 Support for the Dove thermal sensor driver in the Linux thermal ··· 241 241 menu "Samsung thermal drivers" 242 242 depends on ARCH_EXYNOS 243 243 source "drivers/thermal/samsung/Kconfig" 244 + endmenu 245 + 246 + menu "STMicroelectronics thermal drivers" 247 + depends on ARCH_STI && OF 248 + source "drivers/thermal/st/Kconfig" 244 249 endmenu 245 250 246 251 endif
+1
drivers/thermal/Makefile
··· 32 32 obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o 33 33 obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 34 34 obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o 35 + obj-$(CONFIG_ST_THERMAL) += st/
+1 -1
drivers/thermal/cpu_cooling.c
··· 305 305 * @event: value showing cpufreq event for which this function invoked. 306 306 * @data: callback-specific data 307 307 * 308 - * Callback to highjack the notification on cpufreq policy transition. 308 + * Callback to hijack the notification on cpufreq policy transition. 309 309 * Every time there is a change in policy, we will intercept and 310 310 * update the cpufreq policy with thermal constraints. 311 311 *
+60 -7
drivers/thermal/int3403_thermal.c
··· 33 33 struct int3403_sensor { 34 34 struct thermal_zone_device *tzone; 35 35 unsigned long *thresholds; 36 + unsigned long crit_temp; 37 + int crit_trip_id; 38 + unsigned long psv_temp; 39 + int psv_trip_id; 36 40 }; 37 41 38 42 static int sys_get_curr_temp(struct thermal_zone_device *tzone, ··· 83 79 struct acpi_device *device = tzone->devdata; 84 80 struct int3403_sensor *obj = acpi_driver_data(device); 85 81 86 - /* 87 - * get_trip_temp is a mandatory callback but 88 - * PATx method doesn't return any value, so return 89 - * cached value, which was last set from user space. 90 - */ 91 - *temp = obj->thresholds[trip]; 82 + if (trip == obj->crit_trip_id) 83 + *temp = obj->crit_temp; 84 + else if (trip == obj->psv_trip_id) 85 + *temp = obj->psv_temp; 86 + else { 87 + /* 88 + * get_trip_temp is a mandatory callback but 89 + * PATx method doesn't return any value, so return 90 + * cached value, which was last set from user space. 91 + */ 92 + *temp = obj->thresholds[trip]; 93 + } 92 94 93 95 return 0; 94 96 } ··· 102 92 static int sys_get_trip_type(struct thermal_zone_device *thermal, 103 93 int trip, enum thermal_trip_type *type) 104 94 { 95 + struct acpi_device *device = thermal->devdata; 96 + struct int3403_sensor *obj = acpi_driver_data(device); 97 + 105 98 /* Mandatory callback, may not mean much here */ 106 - *type = THERMAL_TRIP_PASSIVE; 99 + if (trip == obj->crit_trip_id) 100 + *type = THERMAL_TRIP_CRITICAL; 101 + else 102 + *type = THERMAL_TRIP_PASSIVE; 107 103 108 104 return 0; 109 105 } ··· 171 155 } 172 156 } 173 157 158 + static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) 159 + { 160 + unsigned long long crt; 161 + acpi_status status; 162 + 163 + status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); 164 + if (ACPI_FAILURE(status)) 165 + return -EIO; 166 + 167 + *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); 168 + 169 + return 0; 170 + } 171 + 172 + static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) 173 + { 174 + unsigned long long psv; 175 + acpi_status status; 176 + 177 + status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); 178 + if (ACPI_FAILURE(status)) 179 + return -EIO; 180 + 181 + *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); 182 + 183 + return 0; 184 + } 185 + 174 186 static int acpi_int3403_add(struct acpi_device *device) 175 187 { 176 188 int result = 0; ··· 238 194 return -ENOMEM; 239 195 trip_mask = BIT(trip_cnt) - 1; 240 196 } 197 + 198 + obj->psv_trip_id = -1; 199 + if (!sys_get_trip_psv(device, &obj->psv_temp)) 200 + obj->psv_trip_id = trip_cnt++; 201 + 202 + obj->crit_trip_id = -1; 203 + if (!sys_get_trip_crt(device, &obj->crit_temp)) 204 + obj->crit_trip_id = trip_cnt++; 205 + 241 206 obj->tzone = thermal_zone_device_register(acpi_device_bid(device), 242 207 trip_cnt, trip_mask, device, &tzone_ops, 243 208 NULL, 0, 0);
+12
drivers/thermal/st/Kconfig
··· 1 + config ST_THERMAL 2 + tristate "Thermal sensors on STMicroelectronics STi series of SoCs" 3 + help 4 + Support for thermal sensors on STMicroelectronics STi series of SoCs. 5 + 6 + config ST_THERMAL_SYSCFG 7 + select ST_THERMAL 8 + tristate "STi series syscfg register access based thermal sensors" 9 + 10 + config ST_THERMAL_MEMMAP 11 + select ST_THERMAL 12 + tristate "STi series memory mapped access based thermal sensors"
+3
drivers/thermal/st/Makefile
··· 1 + obj-$(CONFIG_ST_THERMAL) := st_thermal.o 2 + obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o 3 + obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o
+313
drivers/thermal/st/st_thermal.c
··· 1 + /* 2 + * ST Thermal Sensor Driver core routines 3 + * Author: Ajit Pal Singh <ajitpal.singh@st.com> 4 + * 5 + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited 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 + */ 13 + 14 + #include <linux/clk.h> 15 + #include <linux/module.h> 16 + #include <linux/of.h> 17 + #include <linux/of_device.h> 18 + 19 + #include "st_thermal.h" 20 + 21 + /* The Thermal Framework expects millidegrees */ 22 + #define mcelsius(temp) ((temp) * 1000) 23 + 24 + /* 25 + * Function to allocate regfields which are common 26 + * between syscfg and memory mapped based sensors 27 + */ 28 + int st_thermal_alloc_regfields(struct st_thermal_sensor *sensor) 29 + { 30 + struct device *dev = sensor->dev; 31 + struct regmap *regmap = sensor->regmap; 32 + const struct reg_field *reg_fields = sensor->cdata->reg_fields; 33 + 34 + sensor->dcorrect = devm_regmap_field_alloc(dev, regmap, 35 + reg_fields[DCORRECT]); 36 + 37 + sensor->overflow = devm_regmap_field_alloc(dev, regmap, 38 + reg_fields[OVERFLOW]); 39 + 40 + sensor->temp_data = devm_regmap_field_alloc(dev, regmap, 41 + reg_fields[DATA]); 42 + 43 + if (IS_ERR(sensor->dcorrect) || 44 + IS_ERR(sensor->overflow) || 45 + IS_ERR(sensor->temp_data)) { 46 + dev_err(dev, "failed to allocate common regfields\n"); 47 + return -EINVAL; 48 + } 49 + 50 + return sensor->ops->alloc_regfields(sensor); 51 + } 52 + 53 + static int st_thermal_sensor_on(struct st_thermal_sensor *sensor) 54 + { 55 + int ret; 56 + struct device *dev = sensor->dev; 57 + 58 + ret = clk_prepare_enable(sensor->clk); 59 + if (ret) { 60 + dev_err(dev, "failed to enable clk\n"); 61 + return ret; 62 + } 63 + 64 + ret = sensor->ops->power_ctrl(sensor, POWER_ON); 65 + if (ret) { 66 + dev_err(dev, "failed to power on sensor\n"); 67 + clk_disable_unprepare(sensor->clk); 68 + } 69 + 70 + return ret; 71 + } 72 + 73 + static int st_thermal_sensor_off(struct st_thermal_sensor *sensor) 74 + { 75 + int ret; 76 + 77 + ret = sensor->ops->power_ctrl(sensor, POWER_OFF); 78 + if (ret) 79 + return ret; 80 + 81 + clk_disable_unprepare(sensor->clk); 82 + 83 + return 0; 84 + } 85 + 86 + static int st_thermal_calibration(struct st_thermal_sensor *sensor) 87 + { 88 + int ret; 89 + unsigned int val; 90 + struct device *dev = sensor->dev; 91 + 92 + /* Check if sensor calibration data is already written */ 93 + ret = regmap_field_read(sensor->dcorrect, &val); 94 + if (ret) { 95 + dev_err(dev, "failed to read calibration data\n"); 96 + return ret; 97 + } 98 + 99 + if (!val) { 100 + /* 101 + * Sensor calibration value not set by bootloader, 102 + * default calibration data to be used 103 + */ 104 + ret = regmap_field_write(sensor->dcorrect, 105 + sensor->cdata->calibration_val); 106 + if (ret) 107 + dev_err(dev, "failed to set calibration data\n"); 108 + } 109 + 110 + return ret; 111 + } 112 + 113 + /* Callback to get temperature from HW*/ 114 + static int st_thermal_get_temp(struct thermal_zone_device *th, 115 + unsigned long *temperature) 116 + { 117 + struct st_thermal_sensor *sensor = th->devdata; 118 + struct device *dev = sensor->dev; 119 + unsigned int temp; 120 + unsigned int overflow; 121 + int ret; 122 + 123 + ret = regmap_field_read(sensor->overflow, &overflow); 124 + if (ret) 125 + return ret; 126 + if (overflow) 127 + return -EIO; 128 + 129 + ret = regmap_field_read(sensor->temp_data, &temp); 130 + if (ret) 131 + return ret; 132 + 133 + temp += sensor->cdata->temp_adjust_val; 134 + temp = mcelsius(temp); 135 + 136 + dev_dbg(dev, "temperature: %d\n", temp); 137 + 138 + *temperature = temp; 139 + 140 + return 0; 141 + } 142 + 143 + static int st_thermal_get_trip_type(struct thermal_zone_device *th, 144 + int trip, enum thermal_trip_type *type) 145 + { 146 + struct st_thermal_sensor *sensor = th->devdata; 147 + struct device *dev = sensor->dev; 148 + 149 + switch (trip) { 150 + case 0: 151 + *type = THERMAL_TRIP_CRITICAL; 152 + break; 153 + default: 154 + dev_err(dev, "invalid trip point\n"); 155 + return -EINVAL; 156 + } 157 + 158 + return 0; 159 + } 160 + 161 + static int st_thermal_get_trip_temp(struct thermal_zone_device *th, 162 + int trip, unsigned long *temp) 163 + { 164 + struct st_thermal_sensor *sensor = th->devdata; 165 + struct device *dev = sensor->dev; 166 + 167 + switch (trip) { 168 + case 0: 169 + *temp = mcelsius(sensor->cdata->crit_temp); 170 + break; 171 + default: 172 + dev_err(dev, "Invalid trip point\n"); 173 + return -EINVAL; 174 + } 175 + 176 + return 0; 177 + } 178 + 179 + static struct thermal_zone_device_ops st_tz_ops = { 180 + .get_temp = st_thermal_get_temp, 181 + .get_trip_type = st_thermal_get_trip_type, 182 + .get_trip_temp = st_thermal_get_trip_temp, 183 + }; 184 + 185 + int st_thermal_register(struct platform_device *pdev, 186 + const struct of_device_id *st_thermal_of_match) 187 + { 188 + struct st_thermal_sensor *sensor; 189 + struct device *dev = &pdev->dev; 190 + struct device_node *np = dev->of_node; 191 + const struct of_device_id *match; 192 + 193 + int polling_delay; 194 + int ret; 195 + 196 + if (!np) { 197 + dev_err(dev, "device tree node not found\n"); 198 + return -EINVAL; 199 + } 200 + 201 + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 202 + if (!sensor) 203 + return -ENOMEM; 204 + 205 + sensor->dev = dev; 206 + 207 + match = of_match_device(st_thermal_of_match, dev); 208 + if (!(match && match->data)) 209 + return -EINVAL; 210 + 211 + sensor->cdata = match->data; 212 + if (!sensor->cdata->ops) 213 + return -EINVAL; 214 + 215 + sensor->ops = sensor->cdata->ops; 216 + 217 + ret = sensor->ops->regmap_init(sensor); 218 + if (ret) 219 + return ret; 220 + 221 + ret = st_thermal_alloc_regfields(sensor); 222 + if (ret) 223 + return ret; 224 + 225 + sensor->clk = devm_clk_get(dev, "thermal"); 226 + if (IS_ERR(sensor->clk)) { 227 + dev_err(dev, "failed to fetch clock\n"); 228 + return PTR_ERR(sensor->clk); 229 + } 230 + 231 + if (sensor->ops->register_enable_irq) { 232 + ret = sensor->ops->register_enable_irq(sensor); 233 + if (ret) 234 + return ret; 235 + } 236 + 237 + ret = st_thermal_sensor_on(sensor); 238 + if (ret) 239 + return ret; 240 + 241 + ret = st_thermal_calibration(sensor); 242 + if (ret) 243 + goto sensor_off; 244 + 245 + polling_delay = sensor->ops->register_enable_irq ? 0 : 1000; 246 + 247 + sensor->thermal_dev = 248 + thermal_zone_device_register(dev_name(dev), 1, 0, sensor, 249 + &st_tz_ops, NULL, 0, polling_delay); 250 + if (IS_ERR(sensor->thermal_dev)) { 251 + dev_err(dev, "failed to register thermal zone device\n"); 252 + ret = PTR_ERR(sensor->thermal_dev); 253 + goto sensor_off; 254 + } 255 + 256 + platform_set_drvdata(pdev, sensor); 257 + 258 + return 0; 259 + 260 + sensor_off: 261 + st_thermal_sensor_off(sensor); 262 + 263 + return ret; 264 + } 265 + EXPORT_SYMBOL_GPL(st_thermal_register); 266 + 267 + int st_thermal_unregister(struct platform_device *pdev) 268 + { 269 + struct st_thermal_sensor *sensor = platform_get_drvdata(pdev); 270 + 271 + st_thermal_sensor_off(sensor); 272 + thermal_zone_device_unregister(sensor->thermal_dev); 273 + 274 + return 0; 275 + } 276 + EXPORT_SYMBOL_GPL(st_thermal_unregister); 277 + 278 + static int st_thermal_suspend(struct device *dev) 279 + { 280 + struct platform_device *pdev = to_platform_device(dev); 281 + struct st_thermal_sensor *sensor = platform_get_drvdata(pdev); 282 + 283 + return st_thermal_sensor_off(sensor); 284 + } 285 + 286 + static int st_thermal_resume(struct device *dev) 287 + { 288 + int ret; 289 + struct platform_device *pdev = to_platform_device(dev); 290 + struct st_thermal_sensor *sensor = platform_get_drvdata(pdev); 291 + 292 + ret = st_thermal_sensor_on(sensor); 293 + if (ret) 294 + return ret; 295 + 296 + ret = st_thermal_calibration(sensor); 297 + if (ret) 298 + return ret; 299 + 300 + if (sensor->ops->enable_irq) { 301 + ret = sensor->ops->enable_irq(sensor); 302 + if (ret) 303 + return ret; 304 + } 305 + 306 + return 0; 307 + } 308 + SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume); 309 + EXPORT_SYMBOL_GPL(st_thermal_pm_ops); 310 + 311 + MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>"); 312 + MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver"); 313 + MODULE_LICENSE("GPL v2");
+104
drivers/thermal/st/st_thermal.h
··· 1 + /* 2 + * ST Thermal Sensor Driver for STi series of SoCs 3 + * Author: Ajit Pal Singh <ajitpal.singh@st.com> 4 + * 5 + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited 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 + 13 + #ifndef __STI_THERMAL_SYSCFG_H 14 + #define __STI_THERMAL_SYSCFG_H 15 + 16 + #include <linux/interrupt.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/regmap.h> 19 + #include <linux/thermal.h> 20 + 21 + enum st_thermal_regfield_ids { 22 + INT_THRESH_HI = 0, /* Top two regfield IDs are mutually exclusive */ 23 + TEMP_PWR = 0, 24 + DCORRECT, 25 + OVERFLOW, 26 + DATA, 27 + INT_ENABLE, 28 + 29 + MAX_REGFIELDS 30 + }; 31 + 32 + /* Thermal sensor power states */ 33 + enum st_thermal_power_state { 34 + POWER_OFF = 0, 35 + POWER_ON 36 + }; 37 + 38 + struct st_thermal_sensor; 39 + 40 + /** 41 + * Description of private thermal sensor ops. 42 + * 43 + * @power_ctrl: Function for powering on/off a sensor. Clock to the 44 + * sensor is also controlled from this function. 45 + * @alloc_regfields: Allocate regmap register fields, specific to a sensor. 46 + * @do_memmap_regmap: Memory map the thermal register space and init regmap 47 + * instance or find regmap instance. 48 + * @register_irq: Register an interrupt handler for a sensor. 49 + */ 50 + struct st_thermal_sensor_ops { 51 + int (*power_ctrl)(struct st_thermal_sensor *, enum st_thermal_power_state); 52 + int (*alloc_regfields)(struct st_thermal_sensor *); 53 + int (*regmap_init)(struct st_thermal_sensor *); 54 + int (*register_enable_irq)(struct st_thermal_sensor *); 55 + int (*enable_irq)(struct st_thermal_sensor *); 56 + }; 57 + 58 + /** 59 + * Description of thermal driver compatible data. 60 + * 61 + * @reg_fields: Pointer to the regfields array for a sensor. 62 + * @sys_compat: Pointer to the syscon node compatible string. 63 + * @ops: Pointer to private thermal ops for a sensor. 64 + * @calibration_val: Default calibration value to be written to the DCORRECT 65 + * register field for a sensor. 66 + * @temp_adjust_val: Value to be added/subtracted from the data read from 67 + * the sensor. If value needs to be added please provide a 68 + * positive value and if it is to be subtracted please 69 + * provide a negative value. 70 + * @crit_temp: The temperature beyond which the SoC should be shutdown 71 + * to prevent damage. 72 + */ 73 + struct st_thermal_compat_data { 74 + char *sys_compat; 75 + const struct reg_field *reg_fields; 76 + const struct st_thermal_sensor_ops *ops; 77 + unsigned int calibration_val; 78 + int temp_adjust_val; 79 + int crit_temp; 80 + }; 81 + 82 + struct st_thermal_sensor { 83 + struct device *dev; 84 + struct thermal_zone_device *thermal_dev; 85 + const struct st_thermal_sensor_ops *ops; 86 + const struct st_thermal_compat_data *cdata; 87 + struct clk *clk; 88 + struct regmap *regmap; 89 + struct regmap_field *pwr; 90 + struct regmap_field *dcorrect; 91 + struct regmap_field *overflow; 92 + struct regmap_field *temp_data; 93 + struct regmap_field *int_thresh_hi; 94 + struct regmap_field *int_enable; 95 + int irq; 96 + void __iomem *mmio_base; 97 + }; 98 + 99 + extern int st_thermal_register(struct platform_device *pdev, 100 + const struct of_device_id *st_thermal_of_match); 101 + extern int st_thermal_unregister(struct platform_device *pdev); 102 + extern const struct dev_pm_ops st_thermal_pm_ops; 103 + 104 + #endif /* __STI_RESET_SYSCFG_H */
+209
drivers/thermal/st/st_thermal_memmap.c
··· 1 + /* 2 + * ST Thermal Sensor Driver for memory mapped sensors. 3 + * Author: Ajit Pal Singh <ajitpal.singh@st.com> 4 + * 5 + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited 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 + 13 + #include <linux/of.h> 14 + #include <linux/module.h> 15 + 16 + #include "st_thermal.h" 17 + 18 + #define STIH416_MPE_CONF 0x0 19 + #define STIH416_MPE_STATUS 0x4 20 + #define STIH416_MPE_INT_THRESH 0x8 21 + #define STIH416_MPE_INT_EN 0xC 22 + 23 + /* Power control bits for the memory mapped thermal sensor */ 24 + #define THERMAL_PDN BIT(4) 25 + #define THERMAL_SRSTN BIT(10) 26 + 27 + static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = { 28 + /* 29 + * According to the STIH416 MPE temp sensor data sheet - 30 + * the PDN (Power Down Bit) and SRSTN (Soft Reset Bit) need to be 31 + * written simultaneously for powering on and off the temperature 32 + * sensor. regmap_update_bits() will be used to update the register. 33 + */ 34 + [INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH, 0, 7), 35 + [DCORRECT] = REG_FIELD(STIH416_MPE_CONF, 5, 9), 36 + [OVERFLOW] = REG_FIELD(STIH416_MPE_STATUS, 9, 9), 37 + [DATA] = REG_FIELD(STIH416_MPE_STATUS, 11, 18), 38 + [INT_ENABLE] = REG_FIELD(STIH416_MPE_INT_EN, 0, 0), 39 + }; 40 + 41 + static irqreturn_t st_mmap_thermal_trip_handler(int irq, void *sdata) 42 + { 43 + struct st_thermal_sensor *sensor = sdata; 44 + 45 + thermal_zone_device_update(sensor->thermal_dev); 46 + 47 + return IRQ_HANDLED; 48 + } 49 + 50 + /* Private ops for the Memory Mapped based thermal sensors */ 51 + static int st_mmap_power_ctrl(struct st_thermal_sensor *sensor, 52 + enum st_thermal_power_state power_state) 53 + { 54 + const unsigned int mask = (THERMAL_PDN | THERMAL_SRSTN); 55 + const unsigned int val = power_state ? mask : 0; 56 + 57 + return regmap_update_bits(sensor->regmap, STIH416_MPE_CONF, mask, val); 58 + } 59 + 60 + static int st_mmap_alloc_regfields(struct st_thermal_sensor *sensor) 61 + { 62 + struct device *dev = sensor->dev; 63 + struct regmap *regmap = sensor->regmap; 64 + const struct reg_field *reg_fields = sensor->cdata->reg_fields; 65 + 66 + sensor->int_thresh_hi = devm_regmap_field_alloc(dev, regmap, 67 + reg_fields[INT_THRESH_HI]); 68 + sensor->int_enable = devm_regmap_field_alloc(dev, regmap, 69 + reg_fields[INT_ENABLE]); 70 + 71 + if (IS_ERR(sensor->int_thresh_hi) || IS_ERR(sensor->int_enable)) { 72 + dev_err(dev, "failed to alloc mmap regfields\n"); 73 + return -EINVAL; 74 + } 75 + 76 + return 0; 77 + } 78 + 79 + static int st_mmap_enable_irq(struct st_thermal_sensor *sensor) 80 + { 81 + int ret; 82 + 83 + /* Set upper critical threshold */ 84 + ret = regmap_field_write(sensor->int_thresh_hi, 85 + sensor->cdata->crit_temp - 86 + sensor->cdata->temp_adjust_val); 87 + if (ret) 88 + return ret; 89 + 90 + return regmap_field_write(sensor->int_enable, 1); 91 + } 92 + 93 + static int st_mmap_register_enable_irq(struct st_thermal_sensor *sensor) 94 + { 95 + struct device *dev = sensor->dev; 96 + struct platform_device *pdev = to_platform_device(dev); 97 + int ret; 98 + 99 + sensor->irq = platform_get_irq(pdev, 0); 100 + if (sensor->irq < 0) { 101 + dev_err(dev, "failed to register IRQ\n"); 102 + return sensor->irq; 103 + } 104 + 105 + ret = devm_request_threaded_irq(dev, sensor->irq, 106 + NULL, st_mmap_thermal_trip_handler, 107 + IRQF_TRIGGER_RISING | IRQF_ONESHOT, 108 + dev->driver->name, sensor); 109 + if (ret) { 110 + dev_err(dev, "failed to register IRQ %d\n", sensor->irq); 111 + return ret; 112 + } 113 + 114 + return st_mmap_enable_irq(sensor); 115 + } 116 + 117 + static const struct regmap_config st_416mpe_regmap_config = { 118 + .reg_bits = 32, 119 + .val_bits = 32, 120 + .reg_stride = 4, 121 + }; 122 + 123 + static int st_mmap_regmap_init(struct st_thermal_sensor *sensor) 124 + { 125 + struct device *dev = sensor->dev; 126 + struct platform_device *pdev = to_platform_device(dev); 127 + struct resource *res; 128 + 129 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 130 + if (!res) { 131 + dev_err(dev, "no memory resources defined\n"); 132 + return -ENODEV; 133 + } 134 + 135 + sensor->mmio_base = devm_ioremap_resource(dev, res); 136 + if (IS_ERR(sensor->mmio_base)) { 137 + dev_err(dev, "failed to remap IO\n"); 138 + return PTR_ERR(sensor->mmio_base); 139 + } 140 + 141 + sensor->regmap = devm_regmap_init_mmio(dev, sensor->mmio_base, 142 + &st_416mpe_regmap_config); 143 + if (IS_ERR(sensor->regmap)) { 144 + dev_err(dev, "failed to initialise regmap\n"); 145 + return PTR_ERR(sensor->regmap); 146 + } 147 + 148 + return 0; 149 + } 150 + 151 + static const struct st_thermal_sensor_ops st_mmap_sensor_ops = { 152 + .power_ctrl = st_mmap_power_ctrl, 153 + .alloc_regfields = st_mmap_alloc_regfields, 154 + .regmap_init = st_mmap_regmap_init, 155 + .register_enable_irq = st_mmap_register_enable_irq, 156 + .enable_irq = st_mmap_enable_irq, 157 + }; 158 + 159 + /* Compatible device data stih416 mpe thermal sensor */ 160 + const struct st_thermal_compat_data st_416mpe_cdata = { 161 + .reg_fields = st_mmap_thermal_regfields, 162 + .ops = &st_mmap_sensor_ops, 163 + .calibration_val = 14, 164 + .temp_adjust_val = -95, 165 + .crit_temp = 120, 166 + }; 167 + 168 + /* Compatible device data stih407 thermal sensor */ 169 + const struct st_thermal_compat_data st_407_cdata = { 170 + .reg_fields = st_mmap_thermal_regfields, 171 + .ops = &st_mmap_sensor_ops, 172 + .calibration_val = 16, 173 + .temp_adjust_val = -95, 174 + .crit_temp = 120, 175 + }; 176 + 177 + static struct of_device_id st_mmap_thermal_of_match[] = { 178 + { .compatible = "st,stih416-mpe-thermal", .data = &st_416mpe_cdata }, 179 + { .compatible = "st,stih407-thermal", .data = &st_407_cdata }, 180 + { /* sentinel */ } 181 + }; 182 + MODULE_DEVICE_TABLE(of, st_mmap_thermal_of_match); 183 + 184 + int st_mmap_probe(struct platform_device *pdev) 185 + { 186 + return st_thermal_register(pdev, st_mmap_thermal_of_match); 187 + } 188 + 189 + int st_mmap_remove(struct platform_device *pdev) 190 + { 191 + return st_thermal_unregister(pdev); 192 + } 193 + 194 + static struct platform_driver st_mmap_thermal_driver = { 195 + .driver = { 196 + .name = "st_thermal_mmap", 197 + .owner = THIS_MODULE, 198 + .pm = &st_thermal_pm_ops, 199 + .of_match_table = st_mmap_thermal_of_match, 200 + }, 201 + .probe = st_mmap_probe, 202 + .remove = st_mmap_remove, 203 + }; 204 + 205 + module_platform_driver(st_mmap_thermal_driver); 206 + 207 + MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>"); 208 + MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver"); 209 + MODULE_LICENSE("GPL v2");
+179
drivers/thermal/st/st_thermal_syscfg.c
··· 1 + /* 2 + * ST Thermal Sensor Driver for syscfg based sensors. 3 + * Author: Ajit Pal Singh <ajitpal.singh@st.com> 4 + * 5 + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited 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 + 13 + #include <linux/of.h> 14 + #include <linux/module.h> 15 + #include <linux/mfd/syscon.h> 16 + 17 + #include "st_thermal.h" 18 + 19 + /* STiH415 */ 20 + #define STIH415_SYSCFG_FRONT(num) ((num - 100) * 4) 21 + #define STIH415_SAS_THSENS_CONF STIH415_SYSCFG_FRONT(178) 22 + #define STIH415_SAS_THSENS_STATUS STIH415_SYSCFG_FRONT(198) 23 + #define STIH415_SYSCFG_MPE(num) ((num - 600) * 4) 24 + #define STIH415_MPE_THSENS_CONF STIH415_SYSCFG_MPE(607) 25 + #define STIH415_MPE_THSENS_STATUS STIH415_SYSCFG_MPE(667) 26 + 27 + /* STiH416 */ 28 + #define STIH416_SYSCFG_FRONT(num) ((num - 1000) * 4) 29 + #define STIH416_SAS_THSENS_CONF STIH416_SYSCFG_FRONT(1552) 30 + #define STIH416_SAS_THSENS_STATUS1 STIH416_SYSCFG_FRONT(1554) 31 + #define STIH416_SAS_THSENS_STATUS2 STIH416_SYSCFG_FRONT(1594) 32 + 33 + /* STiD127 */ 34 + #define STID127_SYSCFG_CPU(num) ((num - 700) * 4) 35 + #define STID127_THSENS_CONF STID127_SYSCFG_CPU(743) 36 + #define STID127_THSENS_STATUS STID127_SYSCFG_CPU(767) 37 + 38 + static const struct reg_field st_415sas_regfields[MAX_REGFIELDS] = { 39 + [TEMP_PWR] = REG_FIELD(STIH415_SAS_THSENS_CONF, 9, 9), 40 + [DCORRECT] = REG_FIELD(STIH415_SAS_THSENS_CONF, 4, 8), 41 + [OVERFLOW] = REG_FIELD(STIH415_SAS_THSENS_STATUS, 8, 8), 42 + [DATA] = REG_FIELD(STIH415_SAS_THSENS_STATUS, 10, 16), 43 + }; 44 + 45 + static const struct reg_field st_415mpe_regfields[MAX_REGFIELDS] = { 46 + [TEMP_PWR] = REG_FIELD(STIH415_MPE_THSENS_CONF, 8, 8), 47 + [DCORRECT] = REG_FIELD(STIH415_MPE_THSENS_CONF, 3, 7), 48 + [OVERFLOW] = REG_FIELD(STIH415_MPE_THSENS_STATUS, 9, 9), 49 + [DATA] = REG_FIELD(STIH415_MPE_THSENS_STATUS, 11, 18), 50 + }; 51 + 52 + static const struct reg_field st_416sas_regfields[MAX_REGFIELDS] = { 53 + [TEMP_PWR] = REG_FIELD(STIH416_SAS_THSENS_CONF, 9, 9), 54 + [DCORRECT] = REG_FIELD(STIH416_SAS_THSENS_CONF, 4, 8), 55 + [OVERFLOW] = REG_FIELD(STIH416_SAS_THSENS_STATUS1, 8, 8), 56 + [DATA] = REG_FIELD(STIH416_SAS_THSENS_STATUS2, 10, 16), 57 + }; 58 + 59 + static const struct reg_field st_127_regfields[MAX_REGFIELDS] = { 60 + [TEMP_PWR] = REG_FIELD(STID127_THSENS_CONF, 7, 7), 61 + [DCORRECT] = REG_FIELD(STID127_THSENS_CONF, 2, 6), 62 + [OVERFLOW] = REG_FIELD(STID127_THSENS_STATUS, 9, 9), 63 + [DATA] = REG_FIELD(STID127_THSENS_STATUS, 11, 18), 64 + }; 65 + 66 + /* Private OPs for System Configuration Register based thermal sensors */ 67 + static int st_syscfg_power_ctrl(struct st_thermal_sensor *sensor, 68 + enum st_thermal_power_state power_state) 69 + { 70 + return regmap_field_write(sensor->pwr, power_state); 71 + } 72 + 73 + static int st_syscfg_alloc_regfields(struct st_thermal_sensor *sensor) 74 + { 75 + struct device *dev = sensor->dev; 76 + 77 + sensor->pwr = devm_regmap_field_alloc(dev, sensor->regmap, 78 + sensor->cdata->reg_fields[TEMP_PWR]); 79 + 80 + if (IS_ERR(sensor->pwr)) { 81 + dev_err(dev, "failed to alloc syscfg regfields\n"); 82 + return PTR_ERR(sensor->pwr); 83 + } 84 + 85 + return 0; 86 + } 87 + 88 + static int st_syscfg_regmap_init(struct st_thermal_sensor *sensor) 89 + { 90 + sensor->regmap = 91 + syscon_regmap_lookup_by_compatible(sensor->cdata->sys_compat); 92 + if (IS_ERR(sensor->regmap)) { 93 + dev_err(sensor->dev, "failed to find syscfg regmap\n"); 94 + return PTR_ERR(sensor->regmap); 95 + } 96 + 97 + return 0; 98 + } 99 + 100 + static const struct st_thermal_sensor_ops st_syscfg_sensor_ops = { 101 + .power_ctrl = st_syscfg_power_ctrl, 102 + .alloc_regfields = st_syscfg_alloc_regfields, 103 + .regmap_init = st_syscfg_regmap_init, 104 + }; 105 + 106 + /* Compatible device data for stih415 sas thermal sensor */ 107 + const struct st_thermal_compat_data st_415sas_cdata = { 108 + .sys_compat = "st,stih415-front-syscfg", 109 + .reg_fields = st_415sas_regfields, 110 + .ops = &st_syscfg_sensor_ops, 111 + .calibration_val = 16, 112 + .temp_adjust_val = 20, 113 + .crit_temp = 120, 114 + }; 115 + 116 + /* Compatible device data for stih415 mpe thermal sensor */ 117 + const struct st_thermal_compat_data st_415mpe_cdata = { 118 + .sys_compat = "st,stih415-system-syscfg", 119 + .reg_fields = st_415mpe_regfields, 120 + .ops = &st_syscfg_sensor_ops, 121 + .calibration_val = 16, 122 + .temp_adjust_val = -103, 123 + .crit_temp = 120, 124 + }; 125 + 126 + /* Compatible device data for stih416 sas thermal sensor */ 127 + const struct st_thermal_compat_data st_416sas_cdata = { 128 + .sys_compat = "st,stih416-front-syscfg", 129 + .reg_fields = st_416sas_regfields, 130 + .ops = &st_syscfg_sensor_ops, 131 + .calibration_val = 16, 132 + .temp_adjust_val = 20, 133 + .crit_temp = 120, 134 + }; 135 + 136 + /* Compatible device data for stid127 thermal sensor */ 137 + const struct st_thermal_compat_data st_127_cdata = { 138 + .sys_compat = "st,stid127-cpu-syscfg", 139 + .reg_fields = st_127_regfields, 140 + .ops = &st_syscfg_sensor_ops, 141 + .calibration_val = 8, 142 + .temp_adjust_val = -103, 143 + .crit_temp = 120, 144 + }; 145 + 146 + static struct of_device_id st_syscfg_thermal_of_match[] = { 147 + { .compatible = "st,stih415-sas-thermal", .data = &st_415sas_cdata }, 148 + { .compatible = "st,stih415-mpe-thermal", .data = &st_415mpe_cdata }, 149 + { .compatible = "st,stih416-sas-thermal", .data = &st_416sas_cdata }, 150 + { .compatible = "st,stid127-thermal", .data = &st_127_cdata }, 151 + { /* sentinel */ } 152 + }; 153 + MODULE_DEVICE_TABLE(of, st_syscfg_thermal_of_match); 154 + 155 + int st_syscfg_probe(struct platform_device *pdev) 156 + { 157 + return st_thermal_register(pdev, st_syscfg_thermal_of_match); 158 + } 159 + 160 + int st_syscfg_remove(struct platform_device *pdev) 161 + { 162 + return st_thermal_unregister(pdev); 163 + } 164 + 165 + static struct platform_driver st_syscfg_thermal_driver = { 166 + .driver = { 167 + .name = "st_syscfg_thermal", 168 + .owner = THIS_MODULE, 169 + .pm = &st_thermal_pm_ops, 170 + .of_match_table = st_syscfg_thermal_of_match, 171 + }, 172 + .probe = st_syscfg_probe, 173 + .remove = st_syscfg_remove, 174 + }; 175 + module_platform_driver(st_syscfg_thermal_driver); 176 + 177 + MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>"); 178 + MODULE_DESCRIPTION("STMicroelectronics STi SoC Thermal Sensor Driver"); 179 + MODULE_LICENSE("GPL v2");
+44 -2
include/linux/thermal.h
··· 158 158 char name[THERMAL_NAME_LENGTH]; 159 159 }; 160 160 161 + /** 162 + * struct thermal_zone_device - structure for a thermal zone 163 + * @id: unique id number for each thermal zone 164 + * @type: the thermal zone device type 165 + * @device: &struct device for this thermal zone 166 + * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature 167 + * @trip_type_attrs: attributes for trip points for sysfs: trip type 168 + * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis 169 + * @devdata: private pointer for device private data 170 + * @trips: number of trip points the thermal zone supports 171 + * @passive_delay: number of milliseconds to wait between polls when 172 + * performing passive cooling. Currenty only used by the 173 + * step-wise governor 174 + * @polling_delay: number of milliseconds to wait between polls when 175 + * checking whether trip points have been crossed (0 for 176 + * interrupt driven systems) 177 + * @temperature: current temperature. This is only for core code, 178 + * drivers should use thermal_zone_get_temp() to get the 179 + * current temperature 180 + * @last_temperature: previous temperature read 181 + * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION 182 + * @passive: 1 if you've crossed a passive trip point, 0 otherwise. 183 + * Currenty only used by the step-wise governor. 184 + * @forced_passive: If > 0, temperature at which to switch on all ACPI 185 + * processor cooling devices. Currently only used by the 186 + * step-wise governor. 187 + * @ops: operations this &thermal_zone_device supports 188 + * @tzp: thermal zone parameters 189 + * @governor: pointer to the governor for this thermal zone 190 + * @thermal_instances: list of &struct thermal_instance of this thermal zone 191 + * @idr: &struct idr to generate unique id for this zone's cooling 192 + * devices 193 + * @lock: lock to protect thermal_instances list 194 + * @node: node in thermal_tz_list (in thermal_core.c) 195 + * @poll_queue: delayed work for polling 196 + */ 161 197 struct thermal_zone_device { 162 198 int id; 163 199 char type[THERMAL_NAME_LENGTH]; ··· 215 179 struct thermal_governor *governor; 216 180 struct list_head thermal_instances; 217 181 struct idr idr; 218 - struct mutex lock; /* protect thermal_instances list */ 182 + struct mutex lock; 219 183 struct list_head node; 220 184 struct delayed_work poll_queue; 221 185 }; 222 186 223 - /* Structure that holds thermal governor information */ 187 + /** 188 + * struct thermal_governor - structure that holds thermal governor information 189 + * @name: name of the governor 190 + * @throttle: callback called for every trip point even if temperature is 191 + * below the trip point temperature 192 + * @governor_list: node in thermal_governor_list (in thermal_core.c) 193 + */ 224 194 struct thermal_governor { 225 195 char name[THERMAL_NAME_LENGTH]; 226 196 int (*throttle)(struct thermal_zone_device *tz, int trip);