···11-Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs.22-33-Required parameters:44--------------------55-66-compatible : Should be "st,stih407-thermal"77-88-clock-names : Should be "thermal".99- See: Documentation/devicetree/bindings/resource-names.txt1010-clocks : Phandle of the clock used by the thermal sensor.1111- See: Documentation/devicetree/bindings/clock/clock-bindings.txt1212-1313-Optional parameters:1414--------------------1515-1616-reg : For non-sysconf based sensors, this should be the physical base1717- address and length of the sensor's registers.1818-interrupts : Standard way to define interrupt number.1919- NB: For thermal sensor's for which no interrupt has been2020- defined, a polling delay of 1000ms will be used to read the2121- temperature from device.2222-2323-Example:2424-2525- temp0@91a0000 {2626- compatible = "st,stih407-thermal";2727- reg = <0x91a0000 0x28>;2828- clock-names = "thermal";2929- clocks = <&CLK_SYSIN>;3030- interrupts = <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>;3131- st,passive_cooling_temp = <110>;3232- };
···763763 struct armada_thermal_priv *priv)764764{765765 const char *name = dev_name(&pdev->dev);766766- char *insane_char;767766768767 if (strlen(name) > THERMAL_NAME_LENGTH) {769768 /*···780781 /* Save the name locally */781782 strscpy(priv->zone_name, name, THERMAL_NAME_LENGTH);782783783783- /* Then check there are no '-' or hwmon core will complain */784784- do {785785- insane_char = strpbrk(priv->zone_name, "-");786786- if (insane_char)787787- *insane_char = '_';788788- } while (insane_char);784784+ /* Then ensure there are no '-' or hwmon core will complain */785785+ strreplace(priv->zone_name, '-', '_');789786}790787791788/*
···159159static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };160160161161static int max_hfi_instances;162162+static int hfi_clients_nr;162163static struct hfi_instance *hfi_instances;163164164165static struct hfi_features hfi_features;···478477enable:479478 cpumask_set_cpu(cpu, hfi_instance->cpus);480479481481- /* Enable this HFI instance if this is its first online CPU. */482482- if (cpumask_weight(hfi_instance->cpus) == 1) {480480+ /*481481+ * Enable this HFI instance if this is its first online CPU and482482+ * there are user-space clients of thermal events.483483+ */484484+ if (cpumask_weight(hfi_instance->cpus) == 1 && hfi_clients_nr > 0) {483485 hfi_set_hw_table(hfi_instance);484486 hfi_enable();485487 }···577573 return 0;578574}579575580580-static void hfi_do_enable(void)576576+/*577577+ * If concurrency is not prevented by other means, the HFI enable/disable578578+ * routines must be called under hfi_instance_lock."579579+ */580580+static void hfi_enable_instance(void *ptr)581581+{582582+ hfi_set_hw_table(ptr);583583+ hfi_enable();584584+}585585+586586+static void hfi_disable_instance(void *ptr)587587+{588588+ hfi_disable();589589+}590590+591591+static void hfi_syscore_resume(void)581592{582593 /* This code runs only on the boot CPU. */583594 struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);584595 struct hfi_instance *hfi_instance = info->hfi_instance;585596586597 /* No locking needed. There is no concurrency with CPU online. */587587- hfi_set_hw_table(hfi_instance);588588- hfi_enable();598598+ if (hfi_clients_nr > 0)599599+ hfi_enable_instance(hfi_instance);589600}590601591591-static int hfi_do_disable(void)602602+static int hfi_syscore_suspend(void)592603{593604 /* No locking needed. There is no concurrency with CPU offline. */594605 hfi_disable();···612593}613594614595static struct syscore_ops hfi_pm_ops = {615615- .resume = hfi_do_enable,616616- .suspend = hfi_do_disable,596596+ .resume = hfi_syscore_resume,597597+ .suspend = hfi_syscore_suspend,598598+};599599+600600+static int hfi_thermal_notify(struct notifier_block *nb, unsigned long state,601601+ void *_notify)602602+{603603+ struct thermal_genl_notify *notify = _notify;604604+ struct hfi_instance *hfi_instance;605605+ smp_call_func_t func = NULL;606606+ unsigned int cpu;607607+ int i;608608+609609+ if (notify->mcgrp != THERMAL_GENL_EVENT_GROUP)610610+ return NOTIFY_DONE;611611+612612+ if (state != THERMAL_NOTIFY_BIND && state != THERMAL_NOTIFY_UNBIND)613613+ return NOTIFY_DONE;614614+615615+ mutex_lock(&hfi_instance_lock);616616+617617+ switch (state) {618618+ case THERMAL_NOTIFY_BIND:619619+ if (++hfi_clients_nr == 1)620620+ func = hfi_enable_instance;621621+ break;622622+ case THERMAL_NOTIFY_UNBIND:623623+ if (--hfi_clients_nr == 0)624624+ func = hfi_disable_instance;625625+ break;626626+ }627627+628628+ if (!func)629629+ goto out;630630+631631+ for (i = 0; i < max_hfi_instances; i++) {632632+ hfi_instance = &hfi_instances[i];633633+ if (cpumask_empty(hfi_instance->cpus))634634+ continue;635635+636636+ cpu = cpumask_any(hfi_instance->cpus);637637+ smp_call_function_single(cpu, func, hfi_instance, true);638638+ }639639+640640+out:641641+ mutex_unlock(&hfi_instance_lock);642642+643643+ return NOTIFY_OK;644644+}645645+646646+static struct notifier_block hfi_thermal_nb = {647647+ .notifier_call = hfi_thermal_notify,617648};618649619650void __init intel_hfi_init(void)···697628 if (!hfi_updates_wq)698629 goto err_nomem;699630631631+ /*632632+ * Both thermal core and Intel HFI can not be build as modules.633633+ * As kernel build-in drivers they are initialized before user-space634634+ * starts, hence we can not miss BIND/UNBIND events when applications635635+ * add/remove thermal multicast group to/from a netlink socket.636636+ */637637+ if (thermal_genl_register_notifier(&hfi_thermal_nb))638638+ goto err_nl_notif;639639+700640 register_syscore_ops(&hfi_pm_ops);701641702642 return;643643+644644+err_nl_notif:645645+ destroy_workqueue(hfi_updates_wq);703646704647err_nomem:705648 for (j = 0; j < i; ++j) {
-1
drivers/thermal/k3_bandgap.c
···78787979struct k3_bandgap {8080 void __iomem *base;8181- const struct k3_bandgap_data *conf;8281};83828483/* common data structures */
+81-40
drivers/thermal/loongson2_thermal.c
···1414#include <linux/property.h>1515#include <linux/thermal.h>1616#include <linux/units.h>1717+1718#include "thermal_hwmon.h"18191919-#define LOONGSON2_MAX_SENSOR_SEL_NUM 32020+#define LOONGSON2_MAX_SENSOR_SEL_NUM 320212121-#define LOONGSON2_THSENS_CTRL_HI_REG 0x02222-#define LOONGSON2_THSENS_CTRL_LOW_REG 0x82323-#define LOONGSON2_THSENS_STATUS_REG 0x102424-#define LOONGSON2_THSENS_OUT_REG 0x142222+#define LOONGSON2_THSENS_CTRL_HI_REG 0x02323+#define LOONGSON2_THSENS_CTRL_LOW_REG 0x82424+#define LOONGSON2_THSENS_STATUS_REG 0x102525+#define LOONGSON2_THSENS_OUT_REG 0x1425262626-#define LOONGSON2_THSENS_INT_LO BIT(0)2727-#define LOONGSON2_THSENS_INT_HIGH BIT(1)2828-#define LOONGSON2_THSENS_OUT_MASK 0xFF2727+#define LOONGSON2_THSENS_INT_LO BIT(0)2828+#define LOONGSON2_THSENS_INT_HIGH BIT(1)2929+#define LOONGSON2_THSENS_INT_EN (LOONGSON2_THSENS_INT_LO | \3030+ LOONGSON2_THSENS_INT_HIGH)3131+#define LOONGSON2_THSENS_OUT_MASK 0xFF3232+3333+/*3434+ * This flag is used to indicate the temperature reading3535+ * method of the Loongson-2K20003636+ */3737+#define LS2K2000_THSENS_OUT_FLAG BIT(0)29383039struct loongson2_thermal_chip_data {3131- unsigned int thermal_sensor_sel;4040+ unsigned int thermal_sensor_sel;4141+ unsigned int flags;3242};33433444struct loongson2_thermal_data {3535- void __iomem *regs;4545+ void __iomem *ctrl_reg;4646+ void __iomem *temp_reg;3647 const struct loongson2_thermal_chip_data *chip_data;3748};38493939-static int loongson2_thermal_set(struct loongson2_thermal_data *data,4040- int low, int high, bool enable)5050+static void loongson2_set_ctrl_regs(struct loongson2_thermal_data *data,5151+ int ctrl_data, bool low, bool enable)4152{4242- u64 reg_ctrl = 0;4343- int reg_off = data->chip_data->thermal_sensor_sel * 2;5353+ int reg_ctrl = 0;5454+ int reg_off = data->chip_data->thermal_sensor_sel * 2;5555+ int ctrl_reg = low ? LOONGSON2_THSENS_CTRL_LOW_REG : LOONGSON2_THSENS_CTRL_HI_REG;44564545- low = clamp(-40, low, high);4646- high = clamp(125, low, high);4747-4848- low += HECTO;4949- high += HECTO;5050-5151- reg_ctrl = low;5757+ reg_ctrl = ctrl_data + HECTO;5258 reg_ctrl |= enable ? 0x100 : 0;5353- writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off);5959+ writew(reg_ctrl, data->ctrl_reg + ctrl_reg + reg_off);6060+}54615555- reg_ctrl = high;5656- reg_ctrl |= enable ? 0x100 : 0;5757- writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off);6262+static int loongson2_thermal_set(struct loongson2_thermal_data *data,6363+ int low, int high, bool enable)6464+{6565+ /* Set low temperature threshold */6666+ loongson2_set_ctrl_regs(data, clamp(-40, low, high), true, enable);6767+6868+ /* Set high temperature threshold */6969+ loongson2_set_ctrl_regs(data, clamp(125, low, high), false, enable);58705971 return 0;6072}61736262-static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp)7474+static int loongson2_2k1000_get_temp(struct thermal_zone_device *tz, int *temp)6375{6464- u32 reg_val;7676+ int val;6577 struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);66786767- reg_val = readl(data->regs + LOONGSON2_THSENS_OUT_REG);6868- *temp = ((reg_val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;7979+ val = readl(data->ctrl_reg + LOONGSON2_THSENS_OUT_REG);8080+ *temp = ((val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;8181+8282+ return 0;8383+}8484+8585+static int loongson2_2k2000_get_temp(struct thermal_zone_device *tz, int *temp)8686+{8787+ int val;8888+ struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);8989+9090+ val = readl(data->temp_reg);9191+ *temp = ((val & 0xffff) * 820 / 0x4000 - 311) * KILO;69927093 return 0;7194}···9875 struct thermal_zone_device *tzd = dev;9976 struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd);10077101101- writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +102102- LOONGSON2_THSENS_STATUS_REG);7878+ writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);1037910480 thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED);10581···11290 return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);11391}11492115115-static const struct thermal_zone_device_ops loongson2_of_thermal_ops = {116116- .get_temp = loongson2_thermal_get_temp,9393+static struct thermal_zone_device_ops loongson2_of_thermal_ops = {9494+ .get_temp = loongson2_2k1000_get_temp,11795 .set_trips = loongson2_thermal_set_trips,11896};11997···130108131109 data->chip_data = device_get_match_data(dev);132110133133- data->regs = devm_platform_ioremap_resource(pdev, 0);134134- if (IS_ERR(data->regs))135135- return PTR_ERR(data->regs);111111+ data->ctrl_reg = devm_platform_ioremap_resource(pdev, 0);112112+ if (IS_ERR(data->ctrl_reg))113113+ return PTR_ERR(data->ctrl_reg);114114+115115+ /* The temperature output register is separate for Loongson-2K2000 */116116+ if (data->chip_data->flags & LS2K2000_THSENS_OUT_FLAG) {117117+ data->temp_reg = devm_platform_ioremap_resource(pdev, 1);118118+ if (IS_ERR(data->temp_reg))119119+ return PTR_ERR(data->temp_reg);120120+121121+ loongson2_of_thermal_ops.get_temp = loongson2_2k2000_get_temp;122122+ }136123137124 irq = platform_get_irq(pdev, 0);138125 if (irq < 0)139126 return irq;140127141141- writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +142142- LOONGSON2_THSENS_STATUS_REG);128128+ writeb(LOONGSON2_THSENS_INT_EN, data->ctrl_reg + LOONGSON2_THSENS_STATUS_REG);143129144130 loongson2_thermal_set(data, 0, 0, false);145131146132 for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {147133 tzd = devm_thermal_of_zone_register(dev, i, data,148148- &loongson2_of_thermal_ops);134134+ &loongson2_of_thermal_ops);149135150136 if (!IS_ERR(tzd))151137 break;···165135 }166136167137 ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,168168- IRQF_ONESHOT, "loongson2_thermal", tzd);138138+ IRQF_ONESHOT, "loongson2_thermal", tzd);169139 if (ret < 0)170140 return dev_err_probe(dev, ret, "failed to request alarm irq\n");171141···176146177147static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {178148 .thermal_sensor_sel = 0,149149+ .flags = 0,150150+};151151+152152+static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k2000_data = {153153+ .thermal_sensor_sel = 0,154154+ .flags = LS2K2000_THSENS_OUT_FLAG,179155};180156181157static const struct of_device_id of_loongson2_thermal_match[] = {182158 {183159 .compatible = "loongson,ls2k1000-thermal",184160 .data = &loongson2_thermal_ls2k1000_data,161161+ },162162+ {163163+ .compatible = "loongson,ls2k2000-thermal",164164+ .data = &loongson2_thermal_ls2k2000_data,185165 },186166 { /* end */ }187167};···207167module_platform_driver(loongson2_thermal_driver);208168209169MODULE_DESCRIPTION("Loongson2 thermal driver");170170+MODULE_AUTHOR("Loongson Technology Corporation Limited");210171MODULE_LICENSE("GPL");
···9595 unsigned int enable_alg;9696 u32 node_id;97979898+ if (!qcom_scm_is_available())9999+ return -EPROBE_DEFER;100100+98101 lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL);99102 if (!lmh_data)100103 return -ENOMEM;
-1
drivers/thermal/qcom/qcom-spmi-temp-alarm.c
···7474 long temp;7575 unsigned int thresh;7676 unsigned int stage;7777- unsigned int prev_stage;7877 unsigned int base;7978 /* protects .thresh, .stage and chip registers */8079 struct mutex lock;
···65656666#define TSC_MAX_NUM 567676868-/* Structure for thermal temperature calculation */6969-struct equation_coefs {7070- int a1;7171- int b1;7272- int a2;7373- int b2;7474-};7575-7668struct rcar_gen3_thermal_priv;77697870struct rcar_thermal_info {7979- int ths_tj_1;7171+ int scale;7272+ int adj_below;7373+ int adj_above;8074 void (*read_fuses)(struct rcar_gen3_thermal_priv *priv);8175};82767777+struct equation_set_coef {7878+ int a;7979+ int b;8080+};8181+8382struct rcar_gen3_thermal_tsc {8383+ struct rcar_gen3_thermal_priv *priv;8484 void __iomem *base;8585 struct thermal_zone_device *zone;8686- struct equation_coefs coef;8787- int tj_t;8686+ /* Different coefficients are used depending on a threshold. */8787+ struct {8888+ struct equation_set_coef below;8989+ struct equation_set_coef above;9090+ } coef;8891 int thcode[3];8992};9093···9693 struct thermal_zone_device_ops ops;9794 unsigned int num_tscs;9895 int ptat[3];9696+ int tj_t;9997 const struct rcar_thermal_info *info;10098};10199···115111/*116112 * Linear approximation for temperature117113 *118118- * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a114114+ * [temp] = ((thadj - [reg]) * a) / b + adj115115+ * [reg] = thadj - ([temp] - adj) * b / a119116 *120117 * The constants a and b are calculated using two triplets of int values PTAT121118 * and THCODE. PTAT and THCODE can either be read from hardware or use hard122122- * coded values from driver. The formula to calculate a and b are taken from123123- * BSP and sparsely documented and understood.119119+ * coded values from the driver. The formula to calculate a and b are taken from120120+ * the datasheet. Different calculations are needed for a and b depending on121121+ * if the input variables ([temp] or [reg]) are above or below a threshold. The122122+ * threshold is also calculated from PTAT and THCODE using formulas from the123123+ * datasheet.124124 *125125- * Examining the linear formula and the formula used to calculate constants a126126- * and b while knowing that the span for PTAT and THCODE values are between127127- * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.128128- * Integer also needs to be signed so that leaves 7 bits for binary129129- * fixed point scaling.125125+ * The constant thadj is one of the THCODE values, which one to use depends on126126+ * the threshold and input value.127127+ *128128+ * The constants adj is taken verbatim from the datasheet. Two values exists,129129+ * which one to use depends on the input value and the calculated threshold.130130+ * Furthermore different SoC models supported by the driver have different sets131131+ * of values. The values for each model are stored in the device match data.130132 */131133132132-#define FIXPT_SHIFT 7133133-#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)134134-#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)135135-#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))136136-#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)137137-138138-#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */139139-140140-/* no idea where these constants come from */141141-#define TJ_3 -41142142-143143-static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv,144144- struct rcar_gen3_thermal_tsc *tsc,145145- int ths_tj_1)134134+static void rcar_gen3_thermal_shared_coefs(struct rcar_gen3_thermal_priv *priv)146135{147147- /* TODO: Find documentation and document constant calculation formula */148148-149149- /*150150- * Division is not scaled in BSP and if scaled it might overflow151151- * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled152152- */153153- tsc->tj_t = (FIXPT_INT((priv->ptat[1] - priv->ptat[2]) * (ths_tj_1 - TJ_3))154154- / (priv->ptat[0] - priv->ptat[2])) + FIXPT_INT(TJ_3);155155-156156- tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[2]),157157- tsc->tj_t - FIXPT_INT(TJ_3));158158- tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3;159159-160160- tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[0]),161161- tsc->tj_t - FIXPT_INT(ths_tj_1));162162- tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1;136136+ priv->tj_t =137137+ DIV_ROUND_CLOSEST((priv->ptat[1] - priv->ptat[2]) * priv->info->scale,138138+ priv->ptat[0] - priv->ptat[2])139139+ + priv->info->adj_below;163140}164164-165165-static int rcar_gen3_thermal_round(int temp)141141+static void rcar_gen3_thermal_tsc_coefs(struct rcar_gen3_thermal_priv *priv,142142+ struct rcar_gen3_thermal_tsc *tsc)166143{167167- int result, round_offs;144144+ tsc->coef.below.a = priv->info->scale * (priv->ptat[2] - priv->ptat[1]);145145+ tsc->coef.above.a = priv->info->scale * (priv->ptat[0] - priv->ptat[1]);168146169169- round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :170170- -RCAR3_THERMAL_GRAN / 2;171171- result = (temp + round_offs) / RCAR3_THERMAL_GRAN;172172- return result * RCAR3_THERMAL_GRAN;147147+ tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]);148148+ tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]);173149}174150175151static int rcar_gen3_thermal_get_temp(struct thermal_zone_device *tz, int *temp)176152{177153 struct rcar_gen3_thermal_tsc *tsc = thermal_zone_device_priv(tz);178178- int mcelsius, val;179179- int reg;154154+ struct rcar_gen3_thermal_priv *priv = tsc->priv;155155+ const struct equation_set_coef *coef;156156+ int adj, decicelsius, reg, thcode;180157181158 /* Read register and convert to mili Celsius */182159 reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;183160184184- if (reg <= tsc->thcode[1])185185- val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,186186- tsc->coef.a1);187187- else188188- val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2,189189- tsc->coef.a2);190190- mcelsius = FIXPT_TO_MCELSIUS(val);161161+ if (reg < tsc->thcode[1]) {162162+ adj = priv->info->adj_below;163163+ coef = &tsc->coef.below;164164+ thcode = tsc->thcode[2];165165+ } else {166166+ adj = priv->info->adj_above;167167+ coef = &tsc->coef.above;168168+ thcode = tsc->thcode[0];169169+ }170170+171171+ /*172172+ * The dividend can't be grown as it might overflow, instead shorten the173173+ * divisor to convert to decidegree Celsius. If we convert after the174174+ * division precision is lost as we will scale up from whole degrees175175+ * Celsius.176176+ */177177+ decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10);191178192179 /* Guaranteed operating range is -40C to 125C. */193180194194- /* Round value to device granularity setting */195195- *temp = rcar_gen3_thermal_round(mcelsius);181181+ /* Reporting is done in millidegree Celsius */182182+ *temp = decicelsius * 100 + adj * 1000;196183197184 return 0;198185}···191196static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,192197 int mcelsius)193198{194194- int celsius, val;199199+ struct rcar_gen3_thermal_priv *priv = tsc->priv;200200+ const struct equation_set_coef *coef;201201+ int adj, celsius, thcode;195202196203 celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);197197- if (celsius <= INT_FIXPT(tsc->tj_t))198198- val = celsius * tsc->coef.a1 + tsc->coef.b1;199199- else200200- val = celsius * tsc->coef.a2 + tsc->coef.b2;204204+ if (celsius < priv->tj_t) {205205+ coef = &tsc->coef.below;206206+ adj = priv->info->adj_below;207207+ thcode = tsc->thcode[2];208208+ } else {209209+ coef = &tsc->coef.above;210210+ adj = priv->info->adj_above;211211+ thcode = tsc->thcode[0];212212+ }201213202202- return INT_FIXPT(val);214214+ return thcode - DIV_ROUND_CLOSEST((celsius - adj) * coef->b, coef->a);203215}204216205217static int rcar_gen3_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)···371369}372370373371static const struct rcar_thermal_info rcar_m3w_thermal_info = {374374- .ths_tj_1 = 116,372372+ .scale = 157,373373+ .adj_below = -41,374374+ .adj_above = 116,375375 .read_fuses = rcar_gen3_thermal_read_fuses_gen3,376376};377377378378static const struct rcar_thermal_info rcar_gen3_thermal_info = {379379- .ths_tj_1 = 126,379379+ .scale = 167,380380+ .adj_below = -41,381381+ .adj_above = 126,380382 .read_fuses = rcar_gen3_thermal_read_fuses_gen3,381383};382384383385static const struct rcar_thermal_info rcar_gen4_thermal_info = {384384- .ths_tj_1 = 126,386386+ .scale = 167,387387+ .adj_below = -41,388388+ .adj_above = 126,385389 .read_fuses = rcar_gen3_thermal_read_fuses_gen4,386390};387391···524516 goto error_unregister;525517 }526518519519+ tsc->priv = priv;527520 tsc->base = devm_ioremap_resource(dev, res);528521 if (IS_ERR(tsc->base)) {529522 ret = PTR_ERR(tsc->base);···539530 if (!rcar_gen3_thermal_read_fuses(priv))540531 dev_info(dev, "No calibration values fused, fallback to driver values\n");541532533533+ rcar_gen3_thermal_shared_coefs(priv);534534+542535 for (i = 0; i < priv->num_tscs; i++) {543536 struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];544537545538 rcar_gen3_thermal_init(priv, tsc);546546- rcar_gen3_thermal_calc_coefs(priv, tsc, priv->info->ths_tj_1);539539+ rcar_gen3_thermal_tsc_coefs(priv, tsc);547540548541 zone = devm_thermal_of_zone_register(dev, i, tsc, &priv->ops);549542 if (IS_ERR(zone)) {
+76-44
drivers/thermal/thermal_core.c
···1515#include <linux/slab.h>1616#include <linux/kdev_t.h>1717#include <linux/idr.h>1818+#include <linux/list_sort.h>1819#include <linux/thermal.h>1920#include <linux/reboot.h>2021#include <linux/string.h>···362361}363362364363static void handle_thermal_trip(struct thermal_zone_device *tz,365365- struct thermal_trip *trip)364364+ struct thermal_trip_desc *td,365365+ struct list_head *way_up_list,366366+ struct list_head *way_down_list)366367{368368+ const struct thermal_trip *trip = &td->trip;369369+ int old_threshold;370370+367371 if (trip->temperature == THERMAL_TEMP_INVALID)368372 return;369373370370- if (tz->last_temperature == THERMAL_TEMP_INVALID) {371371- /* Initialization. */372372- trip->threshold = trip->temperature;373373- if (tz->temperature >= trip->threshold)374374- trip->threshold -= trip->hysteresis;375375- } else if (tz->last_temperature < trip->threshold) {374374+ /*375375+ * If the trip temperature or hysteresis has been updated recently,376376+ * the threshold needs to be computed again using the new values.377377+ * However, its initial value still reflects the old ones and that378378+ * is what needs to be compared with the previous zone temperature379379+ * to decide which action to take.380380+ */381381+ old_threshold = td->threshold;382382+ td->threshold = trip->temperature;383383+384384+ if (tz->last_temperature >= old_threshold &&385385+ tz->last_temperature != THERMAL_TEMP_INVALID) {376386 /*377377- * The trip threshold is equal to the trip temperature, unless378378- * the latter has changed in the meantime. In either case,379379- * the trip is crossed if the current zone temperature is at380380- * least equal to its temperature, but otherwise ensure that381381- * the threshold and the trip temperature will be equal.382382- */383383- if (tz->temperature >= trip->temperature) {384384- thermal_notify_tz_trip_up(tz, trip);385385- thermal_debug_tz_trip_up(tz, trip);386386- trip->threshold = trip->temperature - trip->hysteresis;387387- } else {388388- trip->threshold = trip->temperature;389389- }390390- } else {391391- /*392392- * The previous zone temperature was above or equal to the trip393393- * threshold, which would be equal to the "low temperature" of394394- * the trip (its temperature minus its hysteresis), unless the395395- * trip temperature or hysteresis had changed. In either case,396396- * the trip is crossed if the current zone temperature is below397397- * the low temperature of the trip, but otherwise ensure that398398- * the trip threshold will be equal to the low temperature of399399- * the trip.387387+ * Mitigation is under way, so it needs to stop if the zone388388+ * temperature falls below the low temperature of the trip.389389+ * In that case, the trip temperature becomes the new threshold.400390 */401391 if (tz->temperature < trip->temperature - trip->hysteresis) {402402- thermal_notify_tz_trip_down(tz, trip);403403- thermal_debug_tz_trip_down(tz, trip);404404- trip->threshold = trip->temperature;392392+ list_add(&td->notify_list_node, way_down_list);393393+ td->notify_temp = trip->temperature - trip->hysteresis;405394 } else {406406- trip->threshold = trip->temperature - trip->hysteresis;395395+ td->threshold -= trip->hysteresis;407396 }397397+ } else if (tz->temperature >= trip->temperature) {398398+ /*399399+ * There is no mitigation under way, so it needs to be started400400+ * if the zone temperature exceeds the trip one. The new401401+ * threshold is then set to the low temperature of the trip.402402+ */403403+ list_add_tail(&td->notify_list_node, way_up_list);404404+ td->notify_temp = trip->temperature;405405+ td->threshold -= trip->hysteresis;408406 }409407410408 if (trip->type == THERMAL_TRIP_CRITICAL || trip->type == THERMAL_TRIP_HOT)···455455 pos->initialized = false;456456}457457458458+static int thermal_trip_notify_cmp(void *ascending, const struct list_head *a,459459+ const struct list_head *b)460460+{461461+ struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc,462462+ notify_list_node);463463+ struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc,464464+ notify_list_node);465465+ int ret = tdb->notify_temp - tda->notify_temp;466466+467467+ return ascending ? ret : -ret;468468+}469469+458470void __thermal_zone_device_update(struct thermal_zone_device *tz,459471 enum thermal_notify_event event)460472{461461- struct thermal_trip *trip;473473+ struct thermal_trip_desc *td;474474+ LIST_HEAD(way_down_list);475475+ LIST_HEAD(way_up_list);462476463477 if (tz->suspended)464478 return;···486472487473 tz->notify_event = event;488474489489- for_each_trip(tz, trip)490490- handle_thermal_trip(tz, trip);475475+ for_each_trip_desc(tz, td)476476+ handle_thermal_trip(tz, td, &way_up_list, &way_down_list);477477+478478+ list_sort(&way_up_list, &way_up_list, thermal_trip_notify_cmp);479479+ list_for_each_entry(td, &way_up_list, notify_list_node) {480480+ thermal_notify_tz_trip_up(tz, &td->trip);481481+ thermal_debug_tz_trip_up(tz, &td->trip);482482+ }483483+484484+ list_sort(NULL, &way_down_list, thermal_trip_notify_cmp);485485+ list_for_each_entry(td, &way_down_list, notify_list_node) {486486+ thermal_notify_tz_trip_down(tz, &td->trip);487487+ thermal_debug_tz_trip_down(tz, &td->trip);488488+ }491489492490 monitor_thermal_zone(tz);493491}···792766 if (trip_index < 0 || trip_index >= tz->num_trips)793767 return -EINVAL;794768795795- return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index], cdev,769769+ return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index].trip, cdev,796770 upper, lower, weight);797771}798772EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device);···851825 if (trip_index < 0 || trip_index >= tz->num_trips)852826 return -EINVAL;853827854854- return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index], cdev);828828+ return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index].trip, cdev);855829}856830EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device);857831···1247122112481222int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp)12491223{12501250- int i, ret = -EINVAL;12241224+ const struct thermal_trip_desc *td;12251225+ int ret = -EINVAL;1251122612521227 if (tz->ops.get_crit_temp)12531228 return tz->ops.get_crit_temp(tz, temp);1254122912551230 mutex_lock(&tz->lock);1256123112571257- for (i = 0; i < tz->num_trips; i++) {12581258- if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) {12591259- *temp = tz->trips[i].temperature;12321232+ for_each_trip_desc(tz, td) {12331233+ const struct thermal_trip *trip = &td->trip;12341234+12351235+ if (trip->type == THERMAL_TRIP_CRITICAL) {12361236+ *temp = trip->temperature;12601237 ret = 0;12611238 break;12621239 }···13031274 const struct thermal_zone_params *tzp,13041275 int passive_delay, int polling_delay)13051276{12771277+ const struct thermal_trip *trip = trips;13061278 struct thermal_zone_device *tz;12791279+ struct thermal_trip_desc *td;13071280 int id;13081281 int result;13091282 struct thermal_governor *governor;···13701339 tz->device.class = thermal_class;13711340 tz->devdata = devdata;13721341 tz->num_trips = num_trips;13731373- memcpy(tz->trips, trips, num_trips * sizeof(*trips));13421342+ for_each_trip_desc(tz, td)13431343+ td->trip = *trip++;1374134413751345 thermal_set_delay_jiffies(&tz->passive_delay_jiffies, passive_delay);13761346 thermal_set_delay_jiffies(&tz->polling_delay_jiffies, polling_delay);
+117-2
drivers/thermal/thermal_core.h
···1515#include "thermal_netlink.h"1616#include "thermal_debugfs.h"17171818+struct thermal_trip_desc {1919+ struct thermal_trip trip;2020+ struct list_head notify_list_node;2121+ int notify_temp;2222+ int threshold;2323+};2424+2525+/**2626+ * struct thermal_governor - structure that holds thermal governor information2727+ * @name: name of the governor2828+ * @bind_to_tz: callback called when binding to a thermal zone. If it2929+ * returns 0, the governor is bound to the thermal zone,3030+ * otherwise it fails.3131+ * @unbind_from_tz: callback called when a governor is unbound from a3232+ * thermal zone.3333+ * @throttle: callback called for every trip point even if temperature is3434+ * below the trip point temperature3535+ * @update_tz: callback called when thermal zone internals have changed, e.g.3636+ * thermal cooling instance was added/removed3737+ * @governor_list: node in thermal_governor_list (in thermal_core.c)3838+ */3939+struct thermal_governor {4040+ const char *name;4141+ int (*bind_to_tz)(struct thermal_zone_device *tz);4242+ void (*unbind_from_tz)(struct thermal_zone_device *tz);4343+ int (*throttle)(struct thermal_zone_device *tz,4444+ const struct thermal_trip *trip);4545+ void (*update_tz)(struct thermal_zone_device *tz,4646+ enum thermal_notify_event reason);4747+ struct list_head governor_list;4848+};4949+5050+/**5151+ * struct thermal_zone_device - structure for a thermal zone5252+ * @id: unique id number for each thermal zone5353+ * @type: the thermal zone device type5454+ * @device: &struct device for this thermal zone5555+ * @removal: removal completion5656+ * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature5757+ * @trip_type_attrs: attributes for trip points for sysfs: trip type5858+ * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis5959+ * @mode: current mode of this thermal zone6060+ * @devdata: private pointer for device private data6161+ * @num_trips: number of trip points the thermal zone supports6262+ * @passive_delay_jiffies: number of jiffies to wait between polls when6363+ * performing passive cooling.6464+ * @polling_delay_jiffies: number of jiffies to wait between polls when6565+ * checking whether trip points have been crossed (0 for6666+ * interrupt driven systems)6767+ * @temperature: current temperature. This is only for core code,6868+ * drivers should use thermal_zone_get_temp() to get the6969+ * current temperature7070+ * @last_temperature: previous temperature read7171+ * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION7272+ * @passive: 1 if you've crossed a passive trip point, 0 otherwise.7373+ * @prev_low_trip: the low current temperature if you've crossed a passive7474+ trip point.7575+ * @prev_high_trip: the above current temperature if you've crossed a7676+ passive trip point.7777+ * @need_update: if equals 1, thermal_zone_device_update needs to be invoked.7878+ * @ops: operations this &thermal_zone_device supports7979+ * @tzp: thermal zone parameters8080+ * @governor: pointer to the governor for this thermal zone8181+ * @governor_data: private pointer for governor data8282+ * @thermal_instances: list of &struct thermal_instance of this thermal zone8383+ * @ida: &struct ida to generate unique id for this zone's cooling8484+ * devices8585+ * @lock: lock to protect thermal_instances list8686+ * @node: node in thermal_tz_list (in thermal_core.c)8787+ * @poll_queue: delayed work for polling8888+ * @notify_event: Last notification event8989+ * @suspended: thermal zone suspend indicator9090+ * @trips: array of struct thermal_trip objects9191+ */9292+struct thermal_zone_device {9393+ int id;9494+ char type[THERMAL_NAME_LENGTH];9595+ struct device device;9696+ struct completion removal;9797+ struct attribute_group trips_attribute_group;9898+ struct thermal_attr *trip_temp_attrs;9999+ struct thermal_attr *trip_type_attrs;100100+ struct thermal_attr *trip_hyst_attrs;101101+ enum thermal_device_mode mode;102102+ void *devdata;103103+ int num_trips;104104+ unsigned long passive_delay_jiffies;105105+ unsigned long polling_delay_jiffies;106106+ int temperature;107107+ int last_temperature;108108+ int emul_temperature;109109+ int passive;110110+ int prev_low_trip;111111+ int prev_high_trip;112112+ atomic_t need_update;113113+ struct thermal_zone_device_ops ops;114114+ struct thermal_zone_params *tzp;115115+ struct thermal_governor *governor;116116+ void *governor_data;117117+ struct list_head thermal_instances;118118+ struct ida ida;119119+ struct mutex lock;120120+ struct list_head node;121121+ struct delayed_work poll_queue;122122+ enum thermal_notify_event notify_event;123123+ bool suspended;124124+#ifdef CONFIG_THERMAL_DEBUGFS125125+ struct thermal_debugfs *debugfs;126126+#endif127127+ struct thermal_trip_desc trips[] __counted_by(num_trips);128128+};129129+18130/* Default Thermal Governor */19131#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)20132#define DEFAULT_THERMAL_GOVERNOR "step_wise"···232120 enum thermal_notify_event reason);233121234122/* Helpers */235235-#define for_each_trip(__tz, __trip) \236236- for (__trip = __tz->trips; __trip - __tz->trips < __tz->num_trips; __trip++)123123+#define for_each_trip_desc(__tz, __td) \124124+ for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)125125+126126+#define trip_to_trip_desc(__trip) \127127+ container_of(__trip, struct thermal_trip_desc, trip)237128238129void __thermal_zone_set_trips(struct thermal_zone_device *tz);239130int thermal_zone_trip_id(const struct thermal_zone_device *tz,
+4-2
drivers/thermal/thermal_debugfs.c
···753753{754754 struct thermal_debugfs *thermal_dbg = s->private;755755 struct thermal_zone_device *tz = thermal_dbg->tz_dbg.tz;756756- struct thermal_trip *trip;756756+ struct thermal_trip_desc *td;757757 struct tz_episode *tze;758758 const char *type;759759 int trip_id;···766766767767 seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n");768768769769- for_each_trip(tz, trip) {769769+ for_each_trip_desc(tz, td) {770770+ const struct thermal_trip *trip = &td->trip;771771+770772 /*771773 * There is no possible mitigation happening at the772774 * critical trip point, so the stats will be always
+5-3
drivers/thermal/thermal_helpers.c
···5050 mutex_lock(&tz->lock);5151 mutex_lock(&cdev->lock);52525353- trip = &tz->trips[trip_index];5353+ trip = &tz->trips[trip_index].trip;54545555 list_for_each_entry(pos, &tz->thermal_instances, tz_node) {5656 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {···8282 */8383int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)8484{8585- const struct thermal_trip *trip;8585+ const struct thermal_trip_desc *td;8686 int crit_temp = INT_MAX;8787 int ret = -EINVAL;8888···9191 ret = tz->ops.get_temp(tz, temp);92929393 if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {9494- for_each_trip(tz, trip) {9494+ for_each_trip_desc(tz, td) {9595+ const struct thermal_trip *trip = &td->trip;9696+9597 if (trip->type == THERMAL_TRIP_CRITICAL) {9698 crit_temp = trip->temperature;9799 break;
···6161 * struct thermal_trip - representation of a point in temperature domain6262 * @temperature: temperature value in miliCelsius6363 * @hysteresis: relative hysteresis in miliCelsius6464- * @threshold: trip crossing notification threshold miliCelsius6564 * @type: trip point type6665 * @priv: pointer to driver data associated with this trip6766 * @flags: flags representing binary properties of the trip···6869struct thermal_trip {6970 int temperature;7071 int hysteresis;7171- int threshold;7272 enum thermal_trip_type type;7373 u8 flags;7474 void *priv;···78807981#define THERMAL_TRIP_FLAG_RW (THERMAL_TRIP_FLAG_RW_TEMP | \8082 THERMAL_TRIP_FLAG_RW_HYST)8383+8484+struct thermal_zone_device;81858286struct thermal_zone_device_ops {8387 int (*bind) (struct thermal_zone_device *,···124124#ifdef CONFIG_THERMAL_DEBUGFS125125 struct thermal_debugfs *debugfs;126126#endif127127-};128128-129129-/**130130- * struct thermal_zone_device - structure for a thermal zone131131- * @id: unique id number for each thermal zone132132- * @type: the thermal zone device type133133- * @device: &struct device for this thermal zone134134- * @removal: removal completion135135- * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature136136- * @trip_type_attrs: attributes for trip points for sysfs: trip type137137- * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis138138- * @mode: current mode of this thermal zone139139- * @devdata: private pointer for device private data140140- * @num_trips: number of trip points the thermal zone supports141141- * @passive_delay_jiffies: number of jiffies to wait between polls when142142- * performing passive cooling.143143- * @polling_delay_jiffies: number of jiffies to wait between polls when144144- * checking whether trip points have been crossed (0 for145145- * interrupt driven systems)146146- * @temperature: current temperature. This is only for core code,147147- * drivers should use thermal_zone_get_temp() to get the148148- * current temperature149149- * @last_temperature: previous temperature read150150- * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION151151- * @passive: 1 if you've crossed a passive trip point, 0 otherwise.152152- * @prev_low_trip: the low current temperature if you've crossed a passive153153- trip point.154154- * @prev_high_trip: the above current temperature if you've crossed a155155- passive trip point.156156- * @need_update: if equals 1, thermal_zone_device_update needs to be invoked.157157- * @ops: operations this &thermal_zone_device supports158158- * @tzp: thermal zone parameters159159- * @governor: pointer to the governor for this thermal zone160160- * @governor_data: private pointer for governor data161161- * @thermal_instances: list of &struct thermal_instance of this thermal zone162162- * @ida: &struct ida to generate unique id for this zone's cooling163163- * devices164164- * @lock: lock to protect thermal_instances list165165- * @node: node in thermal_tz_list (in thermal_core.c)166166- * @poll_queue: delayed work for polling167167- * @notify_event: Last notification event168168- * @suspended: thermal zone suspend indicator169169- * @trips: array of struct thermal_trip objects170170- */171171-struct thermal_zone_device {172172- int id;173173- char type[THERMAL_NAME_LENGTH];174174- struct device device;175175- struct completion removal;176176- struct attribute_group trips_attribute_group;177177- struct thermal_attr *trip_temp_attrs;178178- struct thermal_attr *trip_type_attrs;179179- struct thermal_attr *trip_hyst_attrs;180180- enum thermal_device_mode mode;181181- void *devdata;182182- int num_trips;183183- unsigned long passive_delay_jiffies;184184- unsigned long polling_delay_jiffies;185185- int temperature;186186- int last_temperature;187187- int emul_temperature;188188- int passive;189189- int prev_low_trip;190190- int prev_high_trip;191191- atomic_t need_update;192192- struct thermal_zone_device_ops ops;193193- struct thermal_zone_params *tzp;194194- struct thermal_governor *governor;195195- void *governor_data;196196- struct list_head thermal_instances;197197- struct ida ida;198198- struct mutex lock;199199- struct list_head node;200200- struct delayed_work poll_queue;201201- enum thermal_notify_event notify_event;202202- bool suspended;203203-#ifdef CONFIG_THERMAL_DEBUGFS204204- struct thermal_debugfs *debugfs;205205-#endif206206- struct thermal_trip trips[] __counted_by(num_trips);207207-};208208-209209-/**210210- * struct thermal_governor - structure that holds thermal governor information211211- * @name: name of the governor212212- * @bind_to_tz: callback called when binding to a thermal zone. If it213213- * returns 0, the governor is bound to the thermal zone,214214- * otherwise it fails.215215- * @unbind_from_tz: callback called when a governor is unbound from a216216- * thermal zone.217217- * @throttle: callback called for every trip point even if temperature is218218- * below the trip point temperature219219- * @update_tz: callback called when thermal zone internals have changed, e.g.220220- * thermal cooling instance was added/removed221221- * @governor_list: node in thermal_governor_list (in thermal_core.c)222222- */223223-struct thermal_governor {224224- const char *name;225225- int (*bind_to_tz)(struct thermal_zone_device *tz);226226- void (*unbind_from_tz)(struct thermal_zone_device *tz);227227- int (*throttle)(struct thermal_zone_device *tz,228228- const struct thermal_trip *trip);229229- void (*update_tz)(struct thermal_zone_device *tz,230230- enum thermal_notify_event reason);231231- struct list_head governor_list;232127};233128234129/* Structure to define Thermal Zone parameters */