···33Required parameters:44-------------------5566-compatible: should be one of: "brcm,bcm2835-thermal",77- "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal"88-reg: Address range of the thermal registers.99-clocks: Phandle of the clock used by the thermal sensor.66+compatible: should be one of: "brcm,bcm2835-thermal",77+ "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal"88+reg: Address range of the thermal registers.99+clocks: Phandle of the clock used by the thermal sensor.1010+#thermal-sensor-cells: should be 0 (see thermal.txt)10111112Example:1313+1414+thermal-zones {1515+ cpu_thermal: cpu-thermal {1616+ polling-delay-passive = <0>;1717+ polling-delay = <1000>;1818+1919+ thermal-sensors = <&thermal>;2020+2121+ trips {2222+ cpu-crit {2323+ temperature = <80000>;2424+ hysteresis = <0>;2525+ type = "critical";2626+ };2727+ };2828+2929+ coefficients = <(-538) 407000>;3030+3131+ cooling-maps {3232+ };3333+ };3434+};12351336thermal: thermal@7e212000 {1437 compatible = "brcm,bcm2835-thermal";1538 reg = <0x7e212000 0x8>;1639 clocks = <&clocks BCM2835_CLOCK_TSENS>;4040+ #thermal-sensor-cells = <0>;1741};
···11+* Dialog DA9062/61 TJUNC Thermal Module22+33+This module is part of the DA9061/DA9062. For more details about entire44+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt55+66+Junction temperature thermal module uses an interrupt signal to identify77+high THERMAL_TRIP_HOT temperatures for the PMIC device.88+99+Required properties:1010+1111+- compatible: should be one of the following valid compatible string lines:1212+ "dlg,da9061-thermal", "dlg,da9062-thermal"1313+ "dlg,da9062-thermal"1414+1515+Optional properties:1616+1717+- polling-delay-passive : Specify the polling period, measured in1818+ milliseconds, between thermal zone device update checks.1919+2020+Example: DA90622121+2222+ pmic0: da9062@58 {2323+ thermal {2424+ compatible = "dlg,da9062-thermal";2525+ polling-delay-passive = <3000>;2626+ };2727+ };2828+2929+Example: DA9061 using a fall-back compatible for the DA9062 onkey driver3030+3131+ pmic0: da9061@58 {3232+ thermal {3333+ compatible = "dlg,da9061-thermal", "dlg,da9062-thermal";3434+ polling-delay-passive = <3000>;3535+ };3636+ };
+15
drivers/thermal/Kconfig
···303303 bound cpufreq cooling device turns active to set CPU frequency low to304304 cool down the CPU.305305306306+config DA9062_THERMAL307307+ tristate "DA9062/DA9061 Dialog Semiconductor thermal driver"308308+ depends on MFD_DA9062 || COMPILE_TEST309309+ depends on OF310310+ help311311+ Enable this for the Dialog Semiconductor thermal sensor driver.312312+ This will report PMIC junction over-temperature for one thermal trip313313+ zone.314314+ Compatible with the DA9062 and DA9061 PMICs.315315+306316config INTEL_POWERCLAMP307317 tristate "Intel PowerClamp idle injection driver"308318 depends on THERMAL···401391 help402392 Enable this option if you want to have support for thermal management403393 controller present in Mediatek SoCs394394+395395+menu "Broadcom thermal drivers"396396+depends on ARCH_BCM || COMPILE_TEST397397+source "drivers/thermal/broadcom/Kconfig"398398+endmenu404399405400menu "Texas Instruments thermal drivers"406401depends on ARCH_HAS_BANDGAP || COMPILE_TEST
···11+config BCM2835_THERMAL22+ tristate "Thermal sensors on bcm2835 SoC"33+ depends on ARCH_BCM2835 || COMPILE_TEST44+ depends on HAS_IOMEM55+ depends on THERMAL_OF66+ help77+ Support for thermal sensors on Broadcom bcm2835 SoCs.88+99+config BCM_NS_THERMAL1010+ tristate "Northstar thermal driver"1111+ depends on ARCH_BCM_IPROC || COMPILE_TEST1212+ help1313+ Northstar is a family of SoCs that includes e.g. BCM4708, BCM47081,1414+ BCM4709 and BCM47094. It contains DMU (Device Management Unit) block1515+ with a thermal sensor that allows checking CPU temperature. This1616+ driver provides support for it.
···11+/*22+ * Driver for Broadcom BCM2835 SoC temperature sensor33+ *44+ * Copyright (C) 2016 Martin Sperl55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License as published by88+ * the Free Software Foundation; either version 2 of the License, or99+ * (at your option) any later version.1010+ *1111+ * This program is distributed in the hope that it will be useful,1212+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1414+ * GNU General Public License for more details.1515+ */1616+1717+#include <linux/clk.h>1818+#include <linux/debugfs.h>1919+#include <linux/device.h>2020+#include <linux/err.h>2121+#include <linux/io.h>2222+#include <linux/kernel.h>2323+#include <linux/module.h>2424+#include <linux/of.h>2525+#include <linux/of_address.h>2626+#include <linux/of_device.h>2727+#include <linux/platform_device.h>2828+#include <linux/thermal.h>2929+3030+#define BCM2835_TS_TSENSCTL 0x003131+#define BCM2835_TS_TSENSSTAT 0x043232+3333+#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)3434+#define BCM2835_TS_TSENSCTL_RSTB BIT(1)3535+3636+/*3737+ * bandgap reference voltage in 6 mV increments3838+ * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV3939+ */4040+#define BCM2835_TS_TSENSCTL_CTRL_BITS 34141+#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 24242+#define BCM2835_TS_TSENSCTL_CTRL_MASK \4343+ GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \4444+ BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \4545+ BCM2835_TS_TSENSCTL_CTRL_SHIFT)4646+#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 14747+#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)4848+#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)4949+#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)5050+#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 85151+#define BCM2835_TS_TSENSCTL_THOLD_BITS 105252+#define BCM2835_TS_TSENSCTL_THOLD_MASK \5353+ GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \5454+ BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \5555+ BCM2835_TS_TSENSCTL_THOLD_SHIFT)5656+/*5757+ * time how long the block to be asserted in reset5858+ * which based on a clock counter (TSENS clock assumed)5959+ */6060+#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 186161+#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 86262+#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)6363+6464+#define BCM2835_TS_TSENSSTAT_DATA_BITS 106565+#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 06666+#define BCM2835_TS_TSENSSTAT_DATA_MASK \6767+ GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \6868+ BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \6969+ BCM2835_TS_TSENSSTAT_DATA_SHIFT)7070+#define BCM2835_TS_TSENSSTAT_VALID BIT(10)7171+#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)7272+7373+struct bcm2835_thermal_data {7474+ struct thermal_zone_device *tz;7575+ void __iomem *regs;7676+ struct clk *clk;7777+ struct dentry *debugfsdir;7878+};7979+8080+static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope)8181+{8282+ return offset + slope * adc;8383+}8484+8585+static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)8686+{8787+ temp -= offset;8888+ temp /= slope;8989+9090+ if (temp < 0)9191+ temp = 0;9292+ if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))9393+ temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;9494+9595+ return temp;9696+}9797+9898+static int bcm2835_thermal_get_temp(void *d, int *temp)9999+{100100+ struct bcm2835_thermal_data *data = d;101101+ u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);102102+103103+ if (!(val & BCM2835_TS_TSENSSTAT_VALID))104104+ return -EIO;105105+106106+ val &= BCM2835_TS_TSENSSTAT_DATA_MASK;107107+108108+ *temp = bcm2835_thermal_adc2temp(109109+ val,110110+ thermal_zone_get_offset(data->tz),111111+ thermal_zone_get_slope(data->tz));112112+113113+ return 0;114114+}115115+116116+static const struct debugfs_reg32 bcm2835_thermal_regs[] = {117117+ {118118+ .name = "ctl",119119+ .offset = 0120120+ },121121+ {122122+ .name = "stat",123123+ .offset = 4124124+ }125125+};126126+127127+static void bcm2835_thermal_debugfs(struct platform_device *pdev)128128+{129129+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);130130+ struct bcm2835_thermal_data *data = tz->devdata;131131+ struct debugfs_regset32 *regset;132132+133133+ data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);134134+ if (!data->debugfsdir)135135+ return;136136+137137+ regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);138138+ if (!regset)139139+ return;140140+141141+ regset->regs = bcm2835_thermal_regs;142142+ regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);143143+ regset->base = data->regs;144144+145145+ debugfs_create_regset32("regset", 0444, data->debugfsdir, regset);146146+}147147+148148+static struct thermal_zone_of_device_ops bcm2835_thermal_ops = {149149+ .get_temp = bcm2835_thermal_get_temp,150150+};151151+152152+/*153153+ * Note: as per Raspberry Foundation FAQ154154+ * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)155155+ * the recommended temperature range for the SoC -40C to +85C156156+ * so the trip limit is set to 80C.157157+ * this applies to all the BCM283X SoC158158+ */159159+160160+static const struct of_device_id bcm2835_thermal_of_match_table[] = {161161+ {162162+ .compatible = "brcm,bcm2835-thermal",163163+ },164164+ {165165+ .compatible = "brcm,bcm2836-thermal",166166+ },167167+ {168168+ .compatible = "brcm,bcm2837-thermal",169169+ },170170+ {},171171+};172172+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);173173+174174+static int bcm2835_thermal_probe(struct platform_device *pdev)175175+{176176+ const struct of_device_id *match;177177+ struct thermal_zone_device *tz;178178+ struct bcm2835_thermal_data *data;179179+ struct resource *res;180180+ int err = 0;181181+ u32 val;182182+ unsigned long rate;183183+184184+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);185185+ if (!data)186186+ return -ENOMEM;187187+188188+ match = of_match_device(bcm2835_thermal_of_match_table,189189+ &pdev->dev);190190+ if (!match)191191+ return -EINVAL;192192+193193+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);194194+ data->regs = devm_ioremap_resource(&pdev->dev, res);195195+ if (IS_ERR(data->regs)) {196196+ err = PTR_ERR(data->regs);197197+ dev_err(&pdev->dev, "Could not get registers: %d\n", err);198198+ return err;199199+ }200200+201201+ data->clk = devm_clk_get(&pdev->dev, NULL);202202+ if (IS_ERR(data->clk)) {203203+ err = PTR_ERR(data->clk);204204+ if (err != -EPROBE_DEFER)205205+ dev_err(&pdev->dev, "Could not get clk: %d\n", err);206206+ return err;207207+ }208208+209209+ err = clk_prepare_enable(data->clk);210210+ if (err)211211+ return err;212212+213213+ rate = clk_get_rate(data->clk);214214+ if ((rate < 1920000) || (rate > 5000000))215215+ dev_warn(&pdev->dev,216216+ "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",217217+ data->clk, data->clk);218218+219219+ /* register of thermal sensor and get info from DT */220220+ tz = thermal_zone_of_sensor_register(&pdev->dev, 0, data,221221+ &bcm2835_thermal_ops);222222+ if (IS_ERR(tz)) {223223+ err = PTR_ERR(tz);224224+ dev_err(&pdev->dev,225225+ "Failed to register the thermal device: %d\n",226226+ err);227227+ goto err_clk;228228+ }229229+230230+ /*231231+ * right now the FW does set up the HW-block, so we are not232232+ * touching the configuration registers.233233+ * But if the HW is not enabled, then set it up234234+ * using "sane" values used by the firmware right now.235235+ */236236+ val = readl(data->regs + BCM2835_TS_TSENSCTL);237237+ if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {238238+ int trip_temp, offset, slope;239239+240240+ slope = thermal_zone_get_slope(tz);241241+ offset = thermal_zone_get_offset(tz);242242+ /*243243+ * For now we deal only with critical, otherwise244244+ * would need to iterate245245+ */246246+ err = tz->ops->get_trip_temp(tz, 0, &trip_temp);247247+ if (err < 0) {248248+ err = PTR_ERR(tz);249249+ dev_err(&pdev->dev,250250+ "Not able to read trip_temp: %d\n",251251+ err);252252+ goto err_tz;253253+ }254254+255255+ /* set bandgap reference voltage and enable voltage regulator */256256+ val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<257257+ BCM2835_TS_TSENSCTL_CTRL_SHIFT) |258258+ BCM2835_TS_TSENSCTL_REGULEN;259259+260260+ /* use the recommended reset duration */261261+ val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);262262+263263+ /* trip_adc value from info */264264+ val |= bcm2835_thermal_temp2adc(trip_temp,265265+ offset,266266+ slope)267267+ << BCM2835_TS_TSENSCTL_THOLD_SHIFT;268268+269269+ /* write the value back to the register as 2 steps */270270+ writel(val, data->regs + BCM2835_TS_TSENSCTL);271271+ val |= BCM2835_TS_TSENSCTL_RSTB;272272+ writel(val, data->regs + BCM2835_TS_TSENSCTL);273273+ }274274+275275+ data->tz = tz;276276+277277+ platform_set_drvdata(pdev, tz);278278+279279+ bcm2835_thermal_debugfs(pdev);280280+281281+ return 0;282282+err_tz:283283+ thermal_zone_of_sensor_unregister(&pdev->dev, tz);284284+err_clk:285285+ clk_disable_unprepare(data->clk);286286+287287+ return err;288288+}289289+290290+static int bcm2835_thermal_remove(struct platform_device *pdev)291291+{292292+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);293293+ struct bcm2835_thermal_data *data = tz->devdata;294294+295295+ debugfs_remove_recursive(data->debugfsdir);296296+ thermal_zone_of_sensor_unregister(&pdev->dev, tz);297297+ clk_disable_unprepare(data->clk);298298+299299+ return 0;300300+}301301+302302+static struct platform_driver bcm2835_thermal_driver = {303303+ .probe = bcm2835_thermal_probe,304304+ .remove = bcm2835_thermal_remove,305305+ .driver = {306306+ .name = "bcm2835_thermal",307307+ .of_match_table = bcm2835_thermal_of_match_table,308308+ },309309+};310310+module_platform_driver(bcm2835_thermal_driver);311311+312312+MODULE_AUTHOR("Martin Sperl");313313+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");314314+MODULE_LICENSE("GPL");
+106
drivers/thermal/broadcom/ns-thermal.c
···11+/*22+ * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ */88+99+#include <linux/module.h>1010+#include <linux/of_address.h>1111+#include <linux/platform_device.h>1212+#include <linux/thermal.h>1313+1414+#define PVTMON_CONTROL0 0x001515+#define PVTMON_CONTROL0_SEL_MASK 0x0000000e1616+#define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x000000001717+#define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e1818+#define PVTMON_STATUS 0x081919+2020+struct ns_thermal {2121+ struct thermal_zone_device *tz;2222+ void __iomem *pvtmon;2323+};2424+2525+static int ns_thermal_get_temp(void *data, int *temp)2626+{2727+ struct ns_thermal *ns_thermal = data;2828+ int offset = thermal_zone_get_offset(ns_thermal->tz);2929+ int slope = thermal_zone_get_slope(ns_thermal->tz);3030+ u32 val;3131+3232+ val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);3333+ if ((val & PVTMON_CONTROL0_SEL_MASK) != PVTMON_CONTROL0_SEL_TEMP_MONITOR) {3434+ /* Clear current mode selection */3535+ val &= ~PVTMON_CONTROL0_SEL_MASK;3636+3737+ /* Set temp monitor mode (it's the default actually) */3838+ val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;3939+4040+ writel(val, ns_thermal->pvtmon + PVTMON_CONTROL0);4141+ }4242+4343+ val = readl(ns_thermal->pvtmon + PVTMON_STATUS);4444+ *temp = slope * val + offset;4545+4646+ return 0;4747+}4848+4949+static const struct thermal_zone_of_device_ops ns_thermal_ops = {5050+ .get_temp = ns_thermal_get_temp,5151+};5252+5353+static int ns_thermal_probe(struct platform_device *pdev)5454+{5555+ struct device *dev = &pdev->dev;5656+ struct ns_thermal *ns_thermal;5757+5858+ ns_thermal = devm_kzalloc(dev, sizeof(*ns_thermal), GFP_KERNEL);5959+ if (!ns_thermal)6060+ return -ENOMEM;6161+6262+ ns_thermal->pvtmon = of_iomap(dev_of_node(dev), 0);6363+ if (WARN_ON(!ns_thermal->pvtmon))6464+ return -ENOENT;6565+6666+ ns_thermal->tz = devm_thermal_zone_of_sensor_register(dev, 0,6767+ ns_thermal,6868+ &ns_thermal_ops);6969+ if (IS_ERR(ns_thermal->tz)) {7070+ iounmap(ns_thermal->pvtmon);7171+ return PTR_ERR(ns_thermal->tz);7272+ }7373+7474+ platform_set_drvdata(pdev, ns_thermal);7575+7676+ return 0;7777+}7878+7979+static int ns_thermal_remove(struct platform_device *pdev)8080+{8181+ struct ns_thermal *ns_thermal = platform_get_drvdata(pdev);8282+8383+ iounmap(ns_thermal->pvtmon);8484+8585+ return 0;8686+}8787+8888+static const struct of_device_id ns_thermal_of_match[] = {8989+ { .compatible = "brcm,ns-thermal", },9090+ {},9191+};9292+MODULE_DEVICE_TABLE(of, ns_thermal_of_match);9393+9494+static struct platform_driver ns_thermal_driver = {9595+ .probe = ns_thermal_probe,9696+ .remove = ns_thermal_remove,9797+ .driver = {9898+ .name = "ns-thermal",9999+ .of_match_table = ns_thermal_of_match,100100+ },101101+};102102+module_platform_driver(ns_thermal_driver);103103+104104+MODULE_AUTHOR("Rafał Miłecki <rafal@milecki.pl>");105105+MODULE_DESCRIPTION("Northstar thermal driver");106106+MODULE_LICENSE("GPL v2");
+315
drivers/thermal/da9062-thermal.c
···11+/*22+ * Thermal device driver for DA9062 and DA906133+ * Copyright (C) 2017 Dialog Semiconductor44+ *55+ * This program is free software; you can redistribute it and/or66+ * modify it under the terms of the GNU General Public License77+ * as published by the Free Software Foundation; either version 288+ * of the License, or (at your option) any later version.99+ *1010+ * This program is distributed in the hope that it will be useful,1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313+ * GNU General Public License for more details.1414+ */1515+1616+/* When over-temperature is reached, an interrupt from the device will be1717+ * triggered. Following this event the interrupt will be disabled and1818+ * periodic transmission of uevents (HOT trip point) should define the1919+ * first level of temperature supervision. It is expected that any final2020+ * implementation of the thermal driver will include a .notify() function2121+ * to implement these uevents to userspace.2222+ *2323+ * These uevents are intended to indicate non-invasive temperature control2424+ * of the system, where the necessary measures for cooling are the2525+ * responsibility of the host software. Once the temperature falls again,2626+ * the IRQ is re-enabled so the start of a new over-temperature event can2727+ * be detected without constant software monitoring.2828+ */2929+3030+#include <linux/errno.h>3131+#include <linux/interrupt.h>3232+#include <linux/module.h>3333+#include <linux/of.h>3434+#include <linux/platform_device.h>3535+#include <linux/regmap.h>3636+#include <linux/thermal.h>3737+#include <linux/workqueue.h>3838+3939+#include <linux/mfd/da9062/core.h>4040+#include <linux/mfd/da9062/registers.h>4141+4242+/* Minimum, maximum and default polling millisecond periods are provided4343+ * here as an example. It is expected that any final implementation to also4444+ * include a modification of these settings to match the required4545+ * application.4646+ */4747+#define DA9062_DEFAULT_POLLING_MS_PERIOD 30004848+#define DA9062_MAX_POLLING_MS_PERIOD 100004949+#define DA9062_MIN_POLLING_MS_PERIOD 10005050+5151+#define DA9062_MILLI_CELSIUS(t) ((t) * 1000)5252+5353+struct da9062_thermal_config {5454+ const char *name;5555+};5656+5757+struct da9062_thermal {5858+ struct da9062 *hw;5959+ struct delayed_work work;6060+ struct thermal_zone_device *zone;6161+ enum thermal_device_mode mode;6262+ struct mutex lock; /* protection for da9062_thermal temperature */6363+ int temperature;6464+ int irq;6565+ const struct da9062_thermal_config *config;6666+ struct device *dev;6767+};6868+6969+static void da9062_thermal_poll_on(struct work_struct *work)7070+{7171+ struct da9062_thermal *thermal = container_of(work,7272+ struct da9062_thermal,7373+ work.work);7474+ unsigned long delay;7575+ unsigned int val;7676+ int ret;7777+7878+ /* clear E_TEMP */7979+ ret = regmap_write(thermal->hw->regmap,8080+ DA9062AA_EVENT_B,8181+ DA9062AA_E_TEMP_MASK);8282+ if (ret < 0) {8383+ dev_err(thermal->dev,8484+ "Cannot clear the TJUNC temperature status\n");8585+ goto err_enable_irq;8686+ }8787+8888+ /* Now read E_TEMP again: it is acting like a status bit.8989+ * If over-temperature, then this status will be true.9090+ * If not over-temperature, this status will be false.9191+ */9292+ ret = regmap_read(thermal->hw->regmap,9393+ DA9062AA_EVENT_B,9494+ &val);9595+ if (ret < 0) {9696+ dev_err(thermal->dev,9797+ "Cannot check the TJUNC temperature status\n");9898+ goto err_enable_irq;9999+ }100100+101101+ if (val & DA9062AA_E_TEMP_MASK) {102102+ mutex_lock(&thermal->lock);103103+ thermal->temperature = DA9062_MILLI_CELSIUS(125);104104+ mutex_unlock(&thermal->lock);105105+ thermal_zone_device_update(thermal->zone,106106+ THERMAL_EVENT_UNSPECIFIED);107107+108108+ delay = msecs_to_jiffies(thermal->zone->passive_delay);109109+ schedule_delayed_work(&thermal->work, delay);110110+ return;111111+ }112112+113113+ mutex_lock(&thermal->lock);114114+ thermal->temperature = DA9062_MILLI_CELSIUS(0);115115+ mutex_unlock(&thermal->lock);116116+ thermal_zone_device_update(thermal->zone,117117+ THERMAL_EVENT_UNSPECIFIED);118118+119119+err_enable_irq:120120+ enable_irq(thermal->irq);121121+}122122+123123+static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)124124+{125125+ struct da9062_thermal *thermal = data;126126+127127+ disable_irq_nosync(thermal->irq);128128+ schedule_delayed_work(&thermal->work, 0);129129+130130+ return IRQ_HANDLED;131131+}132132+133133+static int da9062_thermal_get_mode(struct thermal_zone_device *z,134134+ enum thermal_device_mode *mode)135135+{136136+ struct da9062_thermal *thermal = z->devdata;137137+ *mode = thermal->mode;138138+ return 0;139139+}140140+141141+static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,142142+ int trip,143143+ enum thermal_trip_type *type)144144+{145145+ struct da9062_thermal *thermal = z->devdata;146146+147147+ switch (trip) {148148+ case 0:149149+ *type = THERMAL_TRIP_HOT;150150+ break;151151+ default:152152+ dev_err(thermal->dev,153153+ "Driver does not support more than 1 trip-wire\n");154154+ return -EINVAL;155155+ }156156+157157+ return 0;158158+}159159+160160+static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,161161+ int trip,162162+ int *temp)163163+{164164+ struct da9062_thermal *thermal = z->devdata;165165+166166+ switch (trip) {167167+ case 0:168168+ *temp = DA9062_MILLI_CELSIUS(125);169169+ break;170170+ default:171171+ dev_err(thermal->dev,172172+ "Driver does not support more than 1 trip-wire\n");173173+ return -EINVAL;174174+ }175175+176176+ return 0;177177+}178178+179179+static int da9062_thermal_get_temp(struct thermal_zone_device *z,180180+ int *temp)181181+{182182+ struct da9062_thermal *thermal = z->devdata;183183+184184+ mutex_lock(&thermal->lock);185185+ *temp = thermal->temperature;186186+ mutex_unlock(&thermal->lock);187187+188188+ return 0;189189+}190190+191191+static struct thermal_zone_device_ops da9062_thermal_ops = {192192+ .get_temp = da9062_thermal_get_temp,193193+ .get_mode = da9062_thermal_get_mode,194194+ .get_trip_type = da9062_thermal_get_trip_type,195195+ .get_trip_temp = da9062_thermal_get_trip_temp,196196+};197197+198198+static const struct da9062_thermal_config da9062_config = {199199+ .name = "da9062-thermal",200200+};201201+202202+static const struct of_device_id da9062_compatible_reg_id_table[] = {203203+ { .compatible = "dlg,da9062-thermal", .data = &da9062_config },204204+ { },205205+};206206+207207+MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);208208+209209+static int da9062_thermal_probe(struct platform_device *pdev)210210+{211211+ struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);212212+ struct da9062_thermal *thermal;213213+ unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;214214+ const struct of_device_id *match;215215+ int ret = 0;216216+217217+ match = of_match_node(da9062_compatible_reg_id_table,218218+ pdev->dev.of_node);219219+ if (!match)220220+ return -ENXIO;221221+222222+ if (pdev->dev.of_node) {223223+ if (!of_property_read_u32(pdev->dev.of_node,224224+ "polling-delay-passive",225225+ &pp_tmp)) {226226+ if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||227227+ pp_tmp > DA9062_MAX_POLLING_MS_PERIOD) {228228+ dev_warn(&pdev->dev,229229+ "Out-of-range polling period %d ms\n",230230+ pp_tmp);231231+ pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;232232+ }233233+ }234234+ }235235+236236+ thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),237237+ GFP_KERNEL);238238+ if (!thermal) {239239+ ret = -ENOMEM;240240+ goto err;241241+ }242242+243243+ thermal->config = match->data;244244+ thermal->hw = chip;245245+ thermal->mode = THERMAL_DEVICE_ENABLED;246246+ thermal->dev = &pdev->dev;247247+248248+ INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);249249+ mutex_init(&thermal->lock);250250+251251+ thermal->zone = thermal_zone_device_register(thermal->config->name,252252+ 1, 0, thermal,253253+ &da9062_thermal_ops, NULL, pp_tmp,254254+ 0);255255+ if (IS_ERR(thermal->zone)) {256256+ dev_err(&pdev->dev, "Cannot register thermal zone device\n");257257+ ret = PTR_ERR(thermal->zone);258258+ goto err;259259+ }260260+261261+ dev_dbg(&pdev->dev,262262+ "TJUNC temperature polling period set at %d ms\n",263263+ thermal->zone->passive_delay);264264+265265+ ret = platform_get_irq_byname(pdev, "THERMAL");266266+ if (ret < 0) {267267+ dev_err(&pdev->dev, "Failed to get platform IRQ.\n");268268+ goto err_zone;269269+ }270270+ thermal->irq = ret;271271+272272+ ret = request_threaded_irq(thermal->irq, NULL,273273+ da9062_thermal_irq_handler,274274+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,275275+ "THERMAL", thermal);276276+ if (ret) {277277+ dev_err(&pdev->dev,278278+ "Failed to request thermal device IRQ.\n");279279+ goto err_zone;280280+ }281281+282282+ platform_set_drvdata(pdev, thermal);283283+ return 0;284284+285285+err_zone:286286+ thermal_zone_device_unregister(thermal->zone);287287+err:288288+ return ret;289289+}290290+291291+static int da9062_thermal_remove(struct platform_device *pdev)292292+{293293+ struct da9062_thermal *thermal = platform_get_drvdata(pdev);294294+295295+ free_irq(thermal->irq, thermal);296296+ cancel_delayed_work_sync(&thermal->work);297297+ thermal_zone_device_unregister(thermal->zone);298298+ return 0;299299+}300300+301301+static struct platform_driver da9062_thermal_driver = {302302+ .probe = da9062_thermal_probe,303303+ .remove = da9062_thermal_remove,304304+ .driver = {305305+ .name = "da9062-thermal",306306+ .of_match_table = da9062_compatible_reg_id_table,307307+ },308308+};309309+310310+module_platform_driver(da9062_thermal_driver);311311+312312+MODULE_AUTHOR("Steve Twiss");313313+MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");314314+MODULE_LICENSE("GPL");315315+MODULE_ALIAS("platform:da9062-thermal");
+1-1
drivers/thermal/mtk_thermal.c
···191191};192192193193static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {194194- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2194194+ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3195195};196196197197static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
+184-15
drivers/thermal/rcar_gen3_thermal.c
···2020#include <linux/interrupt.h>2121#include <linux/io.h>2222#include <linux/module.h>2323-#include <linux/mutex.h>2423#include <linux/of_device.h>2524#include <linux/platform_device.h>2625#include <linux/pm_runtime.h>2626+#include <linux/spinlock.h>2727#include <linux/thermal.h>2828+2929+#include "thermal_core.h"28302931/* Register offsets */3032#define REG_GEN3_IRQSTR 0x04···4240#define REG_GEN3_THCODE1 0x504341#define REG_GEN3_THCODE2 0x544442#define REG_GEN3_THCODE3 0x584343+4444+/* IRQ{STR,MSK,EN} bits */4545+#define IRQ_TEMP1 BIT(0)4646+#define IRQ_TEMP2 BIT(1)4747+#define IRQ_TEMP3 BIT(2)4848+#define IRQ_TEMPD1 BIT(3)4949+#define IRQ_TEMPD2 BIT(4)5050+#define IRQ_TEMPD3 BIT(5)45514652/* CTSR bits */4753#define CTSR_PONM BIT(8)···8272 void __iomem *base;8373 struct thermal_zone_device *zone;8474 struct equation_coefs coef;8585- struct mutex lock;7575+ int low;7676+ int high;8677};87788879struct rcar_gen3_thermal_priv {8980 struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];8181+ unsigned int num_tscs;8282+ spinlock_t lock; /* Protect interrupts on and off */8383+ const struct rcar_gen3_thermal_data *data;9084};91859286struct rcar_gen3_thermal_data {···128114129115#define FIXPT_SHIFT 7130116#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)117117+#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)131118#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))132119#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)133120···178163 u32 reg;179164180165 /* Read register and convert to mili Celsius */181181- mutex_lock(&tsc->lock);182182-183166 reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;184167185168 val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);186169 val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);187170 mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2);188188-189189- mutex_unlock(&tsc->lock);190171191172 /* Make sure we are inside specifications */192173 if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125)))···194183 return 0;195184}196185186186+static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,187187+ int mcelsius)188188+{189189+ int celsius, val1, val2;190190+191191+ celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);192192+ val1 = celsius * tsc->coef.a1 + tsc->coef.b1;193193+ val2 = celsius * tsc->coef.a2 + tsc->coef.b2;194194+195195+ return INT_FIXPT((val1 + val2) / 2);196196+}197197+198198+static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)199199+{200200+ struct rcar_gen3_thermal_tsc *tsc = devdata;201201+202202+ low = clamp_val(low, -40000, 125000);203203+ high = clamp_val(high, -40000, 125000);204204+205205+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,206206+ rcar_gen3_thermal_mcelsius_to_temp(tsc, low));207207+208208+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,209209+ rcar_gen3_thermal_mcelsius_to_temp(tsc, high));210210+211211+ tsc->low = low;212212+ tsc->high = high;213213+214214+ return 0;215215+}216216+197217static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {198218 .get_temp = rcar_gen3_thermal_get_temp,219219+ .set_trips = rcar_gen3_thermal_set_trips,199220};221221+222222+static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)223223+{224224+ unsigned int i;225225+ u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0;226226+227227+ for (i = 0; i < priv->num_tscs; i++)228228+ rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val);229229+}230230+231231+static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)232232+{233233+ struct rcar_gen3_thermal_priv *priv = data;234234+ u32 status;235235+ int i, ret = IRQ_HANDLED;236236+237237+ spin_lock(&priv->lock);238238+ for (i = 0; i < priv->num_tscs; i++) {239239+ status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);240240+ rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);241241+ if (status)242242+ ret = IRQ_WAKE_THREAD;243243+ }244244+245245+ if (ret == IRQ_WAKE_THREAD)246246+ rcar_thermal_irq_set(priv, false);247247+248248+ spin_unlock(&priv->lock);249249+250250+ return ret;251251+}252252+253253+static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)254254+{255255+ struct rcar_gen3_thermal_priv *priv = data;256256+ unsigned long flags;257257+ int i;258258+259259+ for (i = 0; i < priv->num_tscs; i++)260260+ thermal_zone_device_update(priv->tscs[i]->zone,261261+ THERMAL_EVENT_UNSPECIFIED);262262+263263+ spin_lock_irqsave(&priv->lock, flags);264264+ rcar_thermal_irq_set(priv, true);265265+ spin_unlock_irqrestore(&priv->lock, flags);266266+267267+ return IRQ_HANDLED;268268+}200269201270static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)202271{···286195 usleep_range(1000, 2000);287196288197 rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);198198+289199 rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);200200+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);201201+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);202202+290203 rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,291204 CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);292205···314219 usleep_range(1000, 2000);315220316221 rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);222222+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);223223+ rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);224224+317225 reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);318226 reg_val |= THCTR_THSST;319227 rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);228228+229229+ usleep_range(1000, 2000);320230}321231322232static const struct rcar_gen3_thermal_data r8a7795_data = {···355255 struct device *dev = &pdev->dev;356256 struct resource *res;357257 struct thermal_zone_device *zone;358358- int ret, i;359359- const struct rcar_gen3_thermal_data *match_data =360360- of_device_get_match_data(dev);258258+ int ret, irq, i;259259+ char *irqname;361260362261 /* default values if FUSEs are missing */363262 /* TODO: Read values from hardware on supported platforms */···371272 if (!priv)372273 return -ENOMEM;373274275275+ priv->data = of_device_get_match_data(dev);276276+277277+ spin_lock_init(&priv->lock);278278+374279 platform_set_drvdata(pdev, priv);280280+281281+ /*282282+ * Request 2 (of the 3 possible) IRQs, the driver only needs to283283+ * to trigger on the low and high trip points of the current284284+ * temp window at this point.285285+ */286286+ for (i = 0; i < 2; i++) {287287+ irq = platform_get_irq(pdev, i);288288+ if (irq < 0)289289+ return irq;290290+291291+ irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",292292+ dev_name(dev), i);293293+ if (!irqname)294294+ return -ENOMEM;295295+296296+ ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq,297297+ rcar_gen3_thermal_irq_thread,298298+ IRQF_SHARED, irqname, priv);299299+ if (ret)300300+ return ret;301301+ }375302376303 pm_runtime_enable(dev);377304 pm_runtime_get_sync(dev);···405280 for (i = 0; i < TSC_MAX_NUM; i++) {406281 struct rcar_gen3_thermal_tsc *tsc;407282283283+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);284284+ if (!res)285285+ break;286286+408287 tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);409288 if (!tsc) {410289 ret = -ENOMEM;411290 goto error_unregister;412291 }413413-414414- res = platform_get_resource(pdev, IORESOURCE_MEM, i);415415- if (!res)416416- break;417292418293 tsc->base = devm_ioremap_resource(dev, res);419294 if (IS_ERR(tsc->base)) {···422297 }423298424299 priv->tscs[i] = tsc;425425- mutex_init(&tsc->lock);426300427427- match_data->thermal_init(tsc);301301+ priv->data->thermal_init(tsc);428302 rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);429303430304 zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,···434310 goto error_unregister;435311 }436312 tsc->zone = zone;313313+314314+ ret = of_thermal_get_ntrips(tsc->zone);315315+ if (ret < 0)316316+ goto error_unregister;317317+318318+ dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);437319 }320320+321321+ priv->num_tscs = i;322322+323323+ if (!priv->num_tscs) {324324+ ret = -ENODEV;325325+ goto error_unregister;326326+ }327327+328328+ rcar_thermal_irq_set(priv, true);438329439330 return 0;440331···459320 return ret;460321}461322323323+static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev)324324+{325325+ struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);326326+327327+ rcar_thermal_irq_set(priv, false);328328+329329+ return 0;330330+}331331+332332+static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)333333+{334334+ struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);335335+ unsigned int i;336336+337337+ for (i = 0; i < priv->num_tscs; i++) {338338+ struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];339339+340340+ priv->data->thermal_init(tsc);341341+ rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);342342+ }343343+344344+ rcar_thermal_irq_set(priv, true);345345+346346+ return 0;347347+}348348+349349+static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend,350350+ rcar_gen3_thermal_resume);351351+462352static struct platform_driver rcar_gen3_thermal_driver = {463353 .driver = {464354 .name = "rcar_gen3_thermal",355355+ .pm = &rcar_gen3_thermal_pm_ops,465356 .of_match_table = rcar_gen3_thermal_dt_ids,466357 },467358 .probe = rcar_gen3_thermal_probe,
···254254 * @ts_data: pointer to struct with thresholds, limits of temperature sensor255255 * @registers: pointer to the list of register offsets and bitfields256256 * @domain: the name of the domain where the sensor is located257257- * @slope: sensor gradient slope info for hotspot extrapolation equation258258- * @constant: sensor gradient const info for hotspot extrapolation equation259257 * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation260258 * with no external influence261259 * @constant_pcb: sensor gradient const info for hotspot extrapolation equation···272274 struct temp_sensor_registers *registers;273275 char *domain;274276 /* for hotspot extrapolation */275275- const int slope;276276- const int constant;277277 const int slope_pcb;278278 const int constant_pcb;279279 int (*register_cooling)(struct ti_bandgap *bgp, int id);