Merge branch 'thermal-soc' into next
authorZhang Rui <rui.zhang@intel.com>
Sat, 6 May 2017 11:31:19 +0000 (19:31 +0800)
committerZhang Rui <rui.zhang@intel.com>
Sat, 6 May 2017 11:31:19 +0000 (19:31 +0800)
19 files changed:
Documentation/devicetree/bindings/thermal/brcm,bcm2835-thermal.txt
Documentation/devicetree/bindings/thermal/brcm,ns-thermal [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/da9062-thermal.txt [new file with mode: 0644]
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/broadcom/Kconfig [new file with mode: 0644]
drivers/thermal/broadcom/Makefile [new file with mode: 0644]
drivers/thermal/broadcom/bcm2835_thermal.c [new file with mode: 0644]
drivers/thermal/broadcom/ns-thermal.c [new file with mode: 0644]
drivers/thermal/da9062-thermal.c [new file with mode: 0644]
drivers/thermal/mtk_thermal.c
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
drivers/thermal/ti-soc-thermal/omap3-thermal-data.c
drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
drivers/thermal/ti-soc-thermal/ti-bandgap.h
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/thermal/ti-soc-thermal/ti-thermal.h

index 474531d2b2c5fc746d625a5725e9a09f3ec19b8a..da8c5b73ad105a5fa5bf1510f5ec1f2d1ab462f9 100644 (file)
@@ -3,15 +3,39 @@ Binding for Thermal Sensor driver for BCM2835 SoCs.
 Required parameters:
 -------------------
 
-compatible:    should be one of: "brcm,bcm2835-thermal",
-               "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal"
-reg:           Address range of the thermal registers.
-clocks:        Phandle of the clock used by the thermal sensor.
+compatible:            should be one of: "brcm,bcm2835-thermal",
+                       "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal"
+reg:                   Address range of the thermal registers.
+clocks:                Phandle of the clock used by the thermal sensor.
+#thermal-sensor-cells: should be 0 (see thermal.txt)
 
 Example:
 
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               polling-delay-passive = <0>;
+               polling-delay = <1000>;
+
+               thermal-sensors = <&thermal>;
+
+               trips {
+                       cpu-crit {
+                               temperature     = <80000>;
+                               hysteresis      = <0>;
+                               type            = "critical";
+                       };
+               };
+
+               coefficients = <(-538)  407000>;
+
+               cooling-maps {
+               };
+       };
+};
+
 thermal: thermal@7e212000 {
        compatible = "brcm,bcm2835-thermal";
        reg = <0x7e212000 0x8>;
        clocks = <&clocks BCM2835_CLOCK_TSENS>;
+       #thermal-sensor-cells = <0>;
 };
diff --git a/Documentation/devicetree/bindings/thermal/brcm,ns-thermal b/Documentation/devicetree/bindings/thermal/brcm,ns-thermal
new file mode 100644 (file)
index 0000000..68e0471
--- /dev/null
@@ -0,0 +1,37 @@
+* Broadcom Northstar Thermal
+
+This binding describes thermal sensor that is part of Northstar's DMU (Device
+Management Unit).
+
+Required properties:
+- compatible : Must be "brcm,ns-thermal"
+- reg : iomem address range of PVTMON registers
+- #thermal-sensor-cells : Should be <0>
+
+Example:
+
+thermal: thermal@1800c2c0 {
+       compatible = "brcm,ns-thermal";
+       reg = <0x1800c2c0 0x10>;
+       #thermal-sensor-cells = <0>;
+};
+
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               polling-delay-passive = <0>;
+               polling-delay = <1000>;
+               coefficients = <(-556) 418000>;
+               thermal-sensors = <&thermal>;
+
+               trips {
+                       cpu-crit {
+                               temperature     = <125000>;
+                               hysteresis      = <0>;
+                               type            = "critical";
+                       };
+               };
+
+               cooling-maps {
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/thermal/da9062-thermal.txt b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt
new file mode 100644 (file)
index 0000000..e241bb5
--- /dev/null
@@ -0,0 +1,36 @@
+* Dialog DA9062/61 TJUNC Thermal Module
+
+This module is part of the DA9061/DA9062. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+
+Junction temperature thermal module uses an interrupt signal to identify
+high THERMAL_TRIP_HOT temperatures for the PMIC device.
+
+Required properties:
+
+- compatible: should be one of the following valid compatible string lines:
+        "dlg,da9061-thermal", "dlg,da9062-thermal"
+        "dlg,da9062-thermal"
+
+Optional properties:
+
+- polling-delay-passive : Specify the polling period, measured in
+    milliseconds, between thermal zone device update checks.
+
+Example: DA9062
+
+       pmic0: da9062@58 {
+               thermal {
+                       compatible = "dlg,da9062-thermal";
+                       polling-delay-passive = <3000>;
+               };
+       };
+
+Example: DA9061 using a fall-back compatible for the DA9062 onkey driver
+
+       pmic0: da9061@58 {
+               thermal {
+                       compatible = "dlg,da9061-thermal", "dlg,da9062-thermal";
+                       polling-delay-passive = <3000>;
+               };
+       };
index 74ef51dfb816bce97d9367d49eed0f7201a882d2..4edc011fe4a5fe45718c033b051ef262c6db6c9a 100644 (file)
@@ -320,6 +320,16 @@ config DB8500_CPUFREQ_COOLING
          bound cpufreq cooling device turns active to set CPU frequency low to
          cool down the CPU.
 
+config DA9062_THERMAL
+       tristate "DA9062/DA9061 Dialog Semiconductor thermal driver"
+       depends on MFD_DA9062 || COMPILE_TEST
+       depends on OF
+       help
+         Enable this for the Dialog Semiconductor thermal sensor driver.
+         This will report PMIC junction over-temperature for one thermal trip
+         zone.
+         Compatible with the DA9062 and DA9061 PMICs.
+
 config INTEL_POWERCLAMP
        tristate "Intel PowerClamp idle injection driver"
        depends on THERMAL
@@ -409,6 +419,11 @@ config MTK_THERMAL
          Enable this option if you want to have support for thermal management
          controller present in Mediatek SoCs
 
+menu "Broadcom thermal drivers"
+depends on ARCH_BCM || COMPILE_TEST
+source "drivers/thermal/broadcom/Kconfig"
+endmenu
+
 menu "Texas Instruments thermal drivers"
 depends on ARCH_HAS_BANDGAP || COMPILE_TEST
 depends on HAS_IOMEM
index 7adae2029355639b03359fb542c6030f93808ab5..e6834061da28c78eeff99d83461fb1b934d75f16 100644 (file)
@@ -27,6 +27,7 @@ thermal_sys-$(CONFIG_CLOCK_THERMAL)   += clock_cooling.o
 thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
 
 # platform thermal drivers
+obj-y                          += broadcom/
 obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM)     += qcom-spmi-temp-alarm.o
 obj-$(CONFIG_SPEAR_THERMAL)    += spear_thermal.o
 obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_IMX_THERMAL)     += imx_thermal.o
 obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
 obj-$(CONFIG_QORIQ_THERMAL)    += qoriq_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)   += db8500_cpufreq_cooling.o
+obj-$(CONFIG_DA9062_THERMAL)   += da9062-thermal.o
 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
 obj-$(CONFIG_X86_PKG_TEMP_THERMAL)     += x86_pkg_temp_thermal.o
 obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE)  += intel_soc_dts_iosf.o
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
new file mode 100644 (file)
index 0000000..ab08af4
--- /dev/null
@@ -0,0 +1,16 @@
+config BCM2835_THERMAL
+       tristate "Thermal sensors on bcm2835 SoC"
+       depends on ARCH_BCM2835 || COMPILE_TEST
+       depends on HAS_IOMEM
+       depends on THERMAL_OF
+       help
+         Support for thermal sensors on Broadcom bcm2835 SoCs.
+
+config BCM_NS_THERMAL
+       tristate "Northstar thermal driver"
+       depends on ARCH_BCM_IPROC || COMPILE_TEST
+       help
+         Northstar is a family of SoCs that includes e.g. BCM4708, BCM47081,
+         BCM4709 and BCM47094. It contains DMU (Device Management Unit) block
+         with a thermal sensor that allows checking CPU temperature. This
+         driver provides support for it.
diff --git a/drivers/thermal/broadcom/Makefile b/drivers/thermal/broadcom/Makefile
new file mode 100644 (file)
index 0000000..c6f62e4
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BCM2835_THERMAL)          += bcm2835_thermal.o
+obj-$(CONFIG_BCM_NS_THERMAL)           += ns-thermal.o
diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c
new file mode 100644 (file)
index 0000000..0ecf808
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Driver for Broadcom BCM2835 SoC temperature sensor
+ *
+ * Copyright (C) 2016 Martin Sperl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define BCM2835_TS_TSENSCTL                    0x00
+#define BCM2835_TS_TSENSSTAT                   0x04
+
+#define BCM2835_TS_TSENSCTL_PRWDW              BIT(0)
+#define BCM2835_TS_TSENSCTL_RSTB               BIT(1)
+
+/*
+ * bandgap reference voltage in 6 mV increments
+ * 000b = 1178 mV, 001b = 1184 mV, ... 111b = 1220 mV
+ */
+#define BCM2835_TS_TSENSCTL_CTRL_BITS          3
+#define BCM2835_TS_TSENSCTL_CTRL_SHIFT         2
+#define BCM2835_TS_TSENSCTL_CTRL_MASK              \
+       GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS +     \
+               BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
+               BCM2835_TS_TSENSCTL_CTRL_SHIFT)
+#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT       1
+#define BCM2835_TS_TSENSCTL_EN_INT             BIT(5)
+#define BCM2835_TS_TSENSCTL_DIRECT             BIT(6)
+#define BCM2835_TS_TSENSCTL_CLR_INT            BIT(7)
+#define BCM2835_TS_TSENSCTL_THOLD_SHIFT                8
+#define BCM2835_TS_TSENSCTL_THOLD_BITS         10
+#define BCM2835_TS_TSENSCTL_THOLD_MASK              \
+       GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS +     \
+               BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
+               BCM2835_TS_TSENSCTL_THOLD_SHIFT)
+/*
+ * time how long the block to be asserted in reset
+ * which based on a clock counter (TSENS clock assumed)
+ */
+#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT     18
+#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS      8
+#define BCM2835_TS_TSENSCTL_REGULEN            BIT(26)
+
+#define BCM2835_TS_TSENSSTAT_DATA_BITS         10
+#define BCM2835_TS_TSENSSTAT_DATA_SHIFT                0
+#define BCM2835_TS_TSENSSTAT_DATA_MASK              \
+       GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS +     \
+               BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
+               BCM2835_TS_TSENSSTAT_DATA_SHIFT)
+#define BCM2835_TS_TSENSSTAT_VALID             BIT(10)
+#define BCM2835_TS_TSENSSTAT_INTERRUPT         BIT(11)
+
+struct bcm2835_thermal_data {
+       struct thermal_zone_device *tz;
+       void __iomem *regs;
+       struct clk *clk;
+       struct dentry *debugfsdir;
+};
+
+static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope)
+{
+       return offset + slope * adc;
+}
+
+static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
+{
+       temp -= offset;
+       temp /= slope;
+
+       if (temp < 0)
+               temp = 0;
+       if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
+               temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
+
+       return temp;
+}
+
+static int bcm2835_thermal_get_temp(void *d, int *temp)
+{
+       struct bcm2835_thermal_data *data = d;
+       u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
+
+       if (!(val & BCM2835_TS_TSENSSTAT_VALID))
+               return -EIO;
+
+       val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
+
+       *temp = bcm2835_thermal_adc2temp(
+               val,
+               thermal_zone_get_offset(data->tz),
+               thermal_zone_get_slope(data->tz));
+
+       return 0;
+}
+
+static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
+       {
+               .name = "ctl",
+               .offset = 0
+       },
+       {
+               .name = "stat",
+               .offset = 4
+       }
+};
+
+static void bcm2835_thermal_debugfs(struct platform_device *pdev)
+{
+       struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+       struct bcm2835_thermal_data *data = tz->devdata;
+       struct debugfs_regset32 *regset;
+
+       data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
+       if (!data->debugfsdir)
+               return;
+
+       regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
+       if (!regset)
+               return;
+
+       regset->regs = bcm2835_thermal_regs;
+       regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
+       regset->base = data->regs;
+
+       debugfs_create_regset32("regset", 0444, data->debugfsdir, regset);
+}
+
+static struct thermal_zone_of_device_ops bcm2835_thermal_ops = {
+       .get_temp = bcm2835_thermal_get_temp,
+};
+
+/*
+ * Note: as per Raspberry Foundation FAQ
+ * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
+ * the recommended temperature range for the SoC -40C to +85C
+ * so the trip limit is set to 80C.
+ * this applies to all the BCM283X SoC
+ */
+
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
+       {
+               .compatible = "brcm,bcm2835-thermal",
+       },
+       {
+               .compatible = "brcm,bcm2836-thermal",
+       },
+       {
+               .compatible = "brcm,bcm2837-thermal",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
+
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct thermal_zone_device *tz;
+       struct bcm2835_thermal_data *data;
+       struct resource *res;
+       int err = 0;
+       u32 val;
+       unsigned long rate;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       match = of_match_device(bcm2835_thermal_of_match_table,
+                               &pdev->dev);
+       if (!match)
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->regs)) {
+               err = PTR_ERR(data->regs);
+               dev_err(&pdev->dev, "Could not get registers: %d\n", err);
+               return err;
+       }
+
+       data->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(data->clk)) {
+               err = PTR_ERR(data->clk);
+               if (err != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Could not get clk: %d\n", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(data->clk);
+       if (err)
+               return err;
+
+       rate = clk_get_rate(data->clk);
+       if ((rate < 1920000) || (rate > 5000000))
+               dev_warn(&pdev->dev,
+                        "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
+                        data->clk, data->clk);
+
+       /* register of thermal sensor and get info from DT */
+       tz = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+                                            &bcm2835_thermal_ops);
+       if (IS_ERR(tz)) {
+               err = PTR_ERR(tz);
+               dev_err(&pdev->dev,
+                       "Failed to register the thermal device: %d\n",
+                       err);
+               goto err_clk;
+       }
+
+       /*
+        * right now the FW does set up the HW-block, so we are not
+        * touching the configuration registers.
+        * But if the HW is not enabled, then set it up
+        * using "sane" values used by the firmware right now.
+        */
+       val = readl(data->regs + BCM2835_TS_TSENSCTL);
+       if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
+               int trip_temp, offset, slope;
+
+               slope = thermal_zone_get_slope(tz);
+               offset = thermal_zone_get_offset(tz);
+               /*
+                * For now we deal only with critical, otherwise
+                * would need to iterate
+                */
+               err = tz->ops->get_trip_temp(tz, 0, &trip_temp);
+               if (err < 0) {
+                       err = PTR_ERR(tz);
+                       dev_err(&pdev->dev,
+                               "Not able to read trip_temp: %d\n",
+                               err);
+                       goto err_tz;
+               }
+
+               /* set bandgap reference voltage and enable voltage regulator */
+               val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
+                      BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
+                     BCM2835_TS_TSENSCTL_REGULEN;
+
+               /* use the recommended reset duration */
+               val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
+
+               /*  trip_adc value from info */
+               val |= bcm2835_thermal_temp2adc(trip_temp,
+                                               offset,
+                                               slope)
+                       << BCM2835_TS_TSENSCTL_THOLD_SHIFT;
+
+               /* write the value back to the register as 2 steps */
+               writel(val, data->regs + BCM2835_TS_TSENSCTL);
+               val |= BCM2835_TS_TSENSCTL_RSTB;
+               writel(val, data->regs + BCM2835_TS_TSENSCTL);
+       }
+
+       data->tz = tz;
+
+       platform_set_drvdata(pdev, tz);
+
+       bcm2835_thermal_debugfs(pdev);
+
+       return 0;
+err_tz:
+       thermal_zone_of_sensor_unregister(&pdev->dev, tz);
+err_clk:
+       clk_disable_unprepare(data->clk);
+
+       return err;
+}
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+       struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+       struct bcm2835_thermal_data *data = tz->devdata;
+
+       debugfs_remove_recursive(data->debugfsdir);
+       thermal_zone_of_sensor_unregister(&pdev->dev, tz);
+       clk_disable_unprepare(data->clk);
+
+       return 0;
+}
+
+static struct platform_driver bcm2835_thermal_driver = {
+       .probe = bcm2835_thermal_probe,
+       .remove = bcm2835_thermal_remove,
+       .driver = {
+               .name = "bcm2835_thermal",
+               .of_match_table = bcm2835_thermal_of_match_table,
+       },
+};
+module_platform_driver(bcm2835_thermal_driver);
+
+MODULE_AUTHOR("Martin Sperl");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/broadcom/ns-thermal.c b/drivers/thermal/broadcom/ns-thermal.c
new file mode 100644 (file)
index 0000000..322e741
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define PVTMON_CONTROL0                                        0x00
+#define PVTMON_CONTROL0_SEL_MASK                       0x0000000e
+#define PVTMON_CONTROL0_SEL_TEMP_MONITOR               0x00000000
+#define PVTMON_CONTROL0_SEL_TEST_MODE                  0x0000000e
+#define PVTMON_STATUS                                  0x08
+
+struct ns_thermal {
+       struct thermal_zone_device *tz;
+       void __iomem *pvtmon;
+};
+
+static int ns_thermal_get_temp(void *data, int *temp)
+{
+       struct ns_thermal *ns_thermal = data;
+       int offset = thermal_zone_get_offset(ns_thermal->tz);
+       int slope = thermal_zone_get_slope(ns_thermal->tz);
+       u32 val;
+
+       val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
+       if ((val & PVTMON_CONTROL0_SEL_MASK) != PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
+               /* Clear current mode selection */
+               val &= ~PVTMON_CONTROL0_SEL_MASK;
+
+               /* Set temp monitor mode (it's the default actually) */
+               val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
+
+               writel(val, ns_thermal->pvtmon + PVTMON_CONTROL0);
+       }
+
+       val = readl(ns_thermal->pvtmon + PVTMON_STATUS);
+       *temp = slope * val + offset;
+
+       return 0;
+}
+
+static const struct thermal_zone_of_device_ops ns_thermal_ops = {
+       .get_temp = ns_thermal_get_temp,
+};
+
+static int ns_thermal_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ns_thermal *ns_thermal;
+
+       ns_thermal = devm_kzalloc(dev, sizeof(*ns_thermal), GFP_KERNEL);
+       if (!ns_thermal)
+               return -ENOMEM;
+
+       ns_thermal->pvtmon = of_iomap(dev_of_node(dev), 0);
+       if (WARN_ON(!ns_thermal->pvtmon))
+               return -ENOENT;
+
+       ns_thermal->tz = devm_thermal_zone_of_sensor_register(dev, 0,
+                                                             ns_thermal,
+                                                             &ns_thermal_ops);
+       if (IS_ERR(ns_thermal->tz)) {
+               iounmap(ns_thermal->pvtmon);
+               return PTR_ERR(ns_thermal->tz);
+       }
+
+       platform_set_drvdata(pdev, ns_thermal);
+
+       return 0;
+}
+
+static int ns_thermal_remove(struct platform_device *pdev)
+{
+       struct ns_thermal *ns_thermal = platform_get_drvdata(pdev);
+
+       iounmap(ns_thermal->pvtmon);
+
+       return 0;
+}
+
+static const struct of_device_id ns_thermal_of_match[] = {
+       { .compatible = "brcm,ns-thermal", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ns_thermal_of_match);
+
+static struct platform_driver ns_thermal_driver = {
+       .probe          = ns_thermal_probe,
+       .remove         = ns_thermal_remove,
+       .driver = {
+               .name = "ns-thermal",
+               .of_match_table = ns_thermal_of_match,
+       },
+};
+module_platform_driver(ns_thermal_driver);
+
+MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>");
+MODULE_DESCRIPTION("Northstar thermal driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
new file mode 100644 (file)
index 0000000..dd8dd94
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Thermal device driver for DA9062 and DA9061
+ * Copyright (C) 2017  Dialog Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* When over-temperature is reached, an interrupt from the device will be
+ * triggered. Following this event the interrupt will be disabled and
+ * periodic transmission of uevents (HOT trip point) should define the
+ * first level of temperature supervision. It is expected that any final
+ * implementation of the thermal driver will include a .notify() function
+ * to implement these uevents to userspace.
+ *
+ * These uevents are intended to indicate non-invasive temperature control
+ * of the system, where the necessary measures for cooling are the
+ * responsibility of the host software. Once the temperature falls again,
+ * the IRQ is re-enabled so the start of a new over-temperature event can
+ * be detected without constant software monitoring.
+ */
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/da9062/core.h>
+#include <linux/mfd/da9062/registers.h>
+
+/* Minimum, maximum and default polling millisecond periods are provided
+ * here as an example. It is expected that any final implementation to also
+ * include a modification of these settings to match the required
+ * application.
+ */
+#define DA9062_DEFAULT_POLLING_MS_PERIOD       3000
+#define DA9062_MAX_POLLING_MS_PERIOD           10000
+#define DA9062_MIN_POLLING_MS_PERIOD           1000
+
+#define DA9062_MILLI_CELSIUS(t)                        ((t) * 1000)
+
+struct da9062_thermal_config {
+       const char *name;
+};
+
+struct da9062_thermal {
+       struct da9062 *hw;
+       struct delayed_work work;
+       struct thermal_zone_device *zone;
+       enum thermal_device_mode mode;
+       struct mutex lock; /* protection for da9062_thermal temperature */
+       int temperature;
+       int irq;
+       const struct da9062_thermal_config *config;
+       struct device *dev;
+};
+
+static void da9062_thermal_poll_on(struct work_struct *work)
+{
+       struct da9062_thermal *thermal = container_of(work,
+                                               struct da9062_thermal,
+                                               work.work);
+       unsigned long delay;
+       unsigned int val;
+       int ret;
+
+       /* clear E_TEMP */
+       ret = regmap_write(thermal->hw->regmap,
+                          DA9062AA_EVENT_B,
+                          DA9062AA_E_TEMP_MASK);
+       if (ret < 0) {
+               dev_err(thermal->dev,
+                       "Cannot clear the TJUNC temperature status\n");
+               goto err_enable_irq;
+       }
+
+       /* Now read E_TEMP again: it is acting like a status bit.
+        * If over-temperature, then this status will be true.
+        * If not over-temperature, this status will be false.
+        */
+       ret = regmap_read(thermal->hw->regmap,
+                         DA9062AA_EVENT_B,
+                         &val);
+       if (ret < 0) {
+               dev_err(thermal->dev,
+                       "Cannot check the TJUNC temperature status\n");
+               goto err_enable_irq;
+       }
+
+       if (val & DA9062AA_E_TEMP_MASK) {
+               mutex_lock(&thermal->lock);
+               thermal->temperature = DA9062_MILLI_CELSIUS(125);
+               mutex_unlock(&thermal->lock);
+               thermal_zone_device_update(thermal->zone,
+                                          THERMAL_EVENT_UNSPECIFIED);
+
+               delay = msecs_to_jiffies(thermal->zone->passive_delay);
+               schedule_delayed_work(&thermal->work, delay);
+               return;
+       }
+
+       mutex_lock(&thermal->lock);
+       thermal->temperature = DA9062_MILLI_CELSIUS(0);
+       mutex_unlock(&thermal->lock);
+       thermal_zone_device_update(thermal->zone,
+                                  THERMAL_EVENT_UNSPECIFIED);
+
+err_enable_irq:
+       enable_irq(thermal->irq);
+}
+
+static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
+{
+       struct da9062_thermal *thermal = data;
+
+       disable_irq_nosync(thermal->irq);
+       schedule_delayed_work(&thermal->work, 0);
+
+       return IRQ_HANDLED;
+}
+
+static int da9062_thermal_get_mode(struct thermal_zone_device *z,
+                                  enum thermal_device_mode *mode)
+{
+       struct da9062_thermal *thermal = z->devdata;
+       *mode = thermal->mode;
+       return 0;
+}
+
+static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
+                                       int trip,
+                                       enum thermal_trip_type *type)
+{
+       struct da9062_thermal *thermal = z->devdata;
+
+       switch (trip) {
+       case 0:
+               *type = THERMAL_TRIP_HOT;
+               break;
+       default:
+               dev_err(thermal->dev,
+                       "Driver does not support more than 1 trip-wire\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
+                                       int trip,
+                                       int *temp)
+{
+       struct da9062_thermal *thermal = z->devdata;
+
+       switch (trip) {
+       case 0:
+               *temp = DA9062_MILLI_CELSIUS(125);
+               break;
+       default:
+               dev_err(thermal->dev,
+                       "Driver does not support more than 1 trip-wire\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int da9062_thermal_get_temp(struct thermal_zone_device *z,
+                                  int *temp)
+{
+       struct da9062_thermal *thermal = z->devdata;
+
+       mutex_lock(&thermal->lock);
+       *temp = thermal->temperature;
+       mutex_unlock(&thermal->lock);
+
+       return 0;
+}
+
+static struct thermal_zone_device_ops da9062_thermal_ops = {
+       .get_temp       = da9062_thermal_get_temp,
+       .get_mode       = da9062_thermal_get_mode,
+       .get_trip_type  = da9062_thermal_get_trip_type,
+       .get_trip_temp  = da9062_thermal_get_trip_temp,
+};
+
+static const struct da9062_thermal_config da9062_config = {
+       .name = "da9062-thermal",
+};
+
+static const struct of_device_id da9062_compatible_reg_id_table[] = {
+       { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
+
+static int da9062_thermal_probe(struct platform_device *pdev)
+{
+       struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
+       struct da9062_thermal *thermal;
+       unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
+       const struct of_device_id *match;
+       int ret = 0;
+
+       match = of_match_node(da9062_compatible_reg_id_table,
+                             pdev->dev.of_node);
+       if (!match)
+               return -ENXIO;
+
+       if (pdev->dev.of_node) {
+               if (!of_property_read_u32(pdev->dev.of_node,
+                                         "polling-delay-passive",
+                                         &pp_tmp)) {
+                       if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
+                           pp_tmp > DA9062_MAX_POLLING_MS_PERIOD) {
+                               dev_warn(&pdev->dev,
+                                        "Out-of-range polling period %d ms\n",
+                                        pp_tmp);
+                               pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
+                       }
+               }
+       }
+
+       thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
+                              GFP_KERNEL);
+       if (!thermal) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       thermal->config = match->data;
+       thermal->hw = chip;
+       thermal->mode = THERMAL_DEVICE_ENABLED;
+       thermal->dev = &pdev->dev;
+
+       INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
+       mutex_init(&thermal->lock);
+
+       thermal->zone = thermal_zone_device_register(thermal->config->name,
+                                       1, 0, thermal,
+                                       &da9062_thermal_ops, NULL, pp_tmp,
+                                       0);
+       if (IS_ERR(thermal->zone)) {
+               dev_err(&pdev->dev, "Cannot register thermal zone device\n");
+               ret = PTR_ERR(thermal->zone);
+               goto err;
+       }
+
+       dev_dbg(&pdev->dev,
+               "TJUNC temperature polling period set at %d ms\n",
+               thermal->zone->passive_delay);
+
+       ret = platform_get_irq_byname(pdev, "THERMAL");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to get platform IRQ.\n");
+               goto err_zone;
+       }
+       thermal->irq = ret;
+
+       ret = request_threaded_irq(thermal->irq, NULL,
+                                  da9062_thermal_irq_handler,
+                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                  "THERMAL", thermal);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Failed to request thermal device IRQ.\n");
+               goto err_zone;
+       }
+
+       platform_set_drvdata(pdev, thermal);
+       return 0;
+
+err_zone:
+       thermal_zone_device_unregister(thermal->zone);
+err:
+       return ret;
+}
+
+static int da9062_thermal_remove(struct platform_device *pdev)
+{
+       struct  da9062_thermal *thermal = platform_get_drvdata(pdev);
+
+       free_irq(thermal->irq, thermal);
+       cancel_delayed_work_sync(&thermal->work);
+       thermal_zone_device_unregister(thermal->zone);
+       return 0;
+}
+
+static struct platform_driver da9062_thermal_driver = {
+       .probe  = da9062_thermal_probe,
+       .remove = da9062_thermal_remove,
+       .driver = {
+               .name   = "da9062-thermal",
+               .of_match_table = da9062_compatible_reg_id_table,
+       },
+};
+
+module_platform_driver(da9062_thermal_driver);
+
+MODULE_AUTHOR("Steve Twiss");
+MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9062-thermal");
index 1aff7fde54b18f217232f0c74cbf3787f55670e0..7737f14846f9e77b0515093d33d13a19c96bf13a 100644 (file)
@@ -191,7 +191,7 @@ static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
 };
 
 static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
-       TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2
+       TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
 };
 
 static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
index d33c845244b1d819b774ed482f78665013ee5203..37fcefd06d9f81b4eb1238634103b5e1ab06a5c3 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
 #include <linux/thermal.h>
 
+#include "thermal_core.h"
+
 /* Register offsets */
 #define REG_GEN3_IRQSTR                0x04
 #define REG_GEN3_IRQMSK                0x08
 #define REG_GEN3_THCODE2       0x54
 #define REG_GEN3_THCODE3       0x58
 
+/* IRQ{STR,MSK,EN} bits */
+#define IRQ_TEMP1              BIT(0)
+#define IRQ_TEMP2              BIT(1)
+#define IRQ_TEMP3              BIT(2)
+#define IRQ_TEMPD1             BIT(3)
+#define IRQ_TEMPD2             BIT(4)
+#define IRQ_TEMPD3             BIT(5)
+
 /* CTSR bits */
 #define CTSR_PONM      BIT(8)
 #define CTSR_AOUT      BIT(7)
@@ -72,11 +82,15 @@ struct rcar_gen3_thermal_tsc {
        void __iomem *base;
        struct thermal_zone_device *zone;
        struct equation_coefs coef;
-       struct mutex lock;
+       int low;
+       int high;
 };
 
 struct rcar_gen3_thermal_priv {
        struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
+       unsigned int num_tscs;
+       spinlock_t lock; /* Protect interrupts on and off */
+       const struct rcar_gen3_thermal_data *data;
 };
 
 struct rcar_gen3_thermal_data {
@@ -114,6 +128,7 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
 
 #define FIXPT_SHIFT 7
 #define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
+#define INT_FIXPT(_x) ((_x) >> FIXPT_SHIFT)
 #define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
 #define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
 
@@ -163,16 +178,12 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
        u32 reg;
 
        /* Read register and convert to mili Celsius */
-       mutex_lock(&tsc->lock);
-
        reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
 
        val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);
        val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);
        mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2);
 
-       mutex_unlock(&tsc->lock);
-
        /* Make sure we are inside specifications */
        if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125)))
                return -EIO;
@@ -183,10 +194,90 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
        return 0;
 }
 
+static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
+                                             int mcelsius)
+{
+       int celsius, val1, val2;
+
+       celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
+       val1 = celsius * tsc->coef.a1 + tsc->coef.b1;
+       val2 = celsius * tsc->coef.a2 + tsc->coef.b2;
+
+       return INT_FIXPT((val1 + val2) / 2);
+}
+
+static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
+{
+       struct rcar_gen3_thermal_tsc *tsc = devdata;
+
+       low = clamp_val(low, -40000, 125000);
+       high = clamp_val(high, -40000, 125000);
+
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
+                               rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
+
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
+                               rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
+
+       tsc->low = low;
+       tsc->high = high;
+
+       return 0;
+}
+
 static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
        .get_temp       = rcar_gen3_thermal_get_temp,
+       .set_trips      = rcar_gen3_thermal_set_trips,
 };
 
+static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
+{
+       unsigned int i;
+       u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0;
+
+       for (i = 0; i < priv->num_tscs; i++)
+               rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val);
+}
+
+static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
+{
+       struct rcar_gen3_thermal_priv *priv = data;
+       u32 status;
+       int i, ret = IRQ_HANDLED;
+
+       spin_lock(&priv->lock);
+       for (i = 0; i < priv->num_tscs; i++) {
+               status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
+               rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
+               if (status)
+                       ret = IRQ_WAKE_THREAD;
+       }
+
+       if (ret == IRQ_WAKE_THREAD)
+               rcar_thermal_irq_set(priv, false);
+
+       spin_unlock(&priv->lock);
+
+       return ret;
+}
+
+static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
+{
+       struct rcar_gen3_thermal_priv *priv = data;
+       unsigned long flags;
+       int i;
+
+       for (i = 0; i < priv->num_tscs; i++)
+               thermal_zone_device_update(priv->tscs[i]->zone,
+                                          THERMAL_EVENT_UNSPECIFIED);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       rcar_thermal_irq_set(priv, true);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
 static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
 {
        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  CTSR_THBGR);
@@ -195,7 +286,11 @@ static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
        usleep_range(1000, 2000);
 
        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
+
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
+
        rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
                                CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
 
@@ -219,9 +314,14 @@ static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
        usleep_range(1000, 2000);
 
        rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
+
        reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
        reg_val |= THCTR_THSST;
        rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
+
+       usleep_range(1000, 2000);
 }
 
 static const struct rcar_gen3_thermal_data r8a7795_data = {
@@ -255,9 +355,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct thermal_zone_device *zone;
-       int ret, i;
-       const struct rcar_gen3_thermal_data *match_data =
-               of_device_get_match_data(dev);
+       int ret, irq, i;
+       char *irqname;
 
        /* default values if FUSEs are missing */
        /* TODO: Read values from hardware on supported platforms */
@@ -272,24 +371,50 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       priv->data = of_device_get_match_data(dev);
+
+       spin_lock_init(&priv->lock);
+
        platform_set_drvdata(pdev, priv);
 
+       /*
+        * Request 2 (of the 3 possible) IRQs, the driver only needs to
+        * to trigger on the low and high trip points of the current
+        * temp window at this point.
+        */
+       for (i = 0; i < 2; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0)
+                       return irq;
+
+               irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
+                                        dev_name(dev), i);
+               if (!irqname)
+                       return -ENOMEM;
+
+               ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq,
+                                               rcar_gen3_thermal_irq_thread,
+                                               IRQF_SHARED, irqname, priv);
+               if (ret)
+                       return ret;
+       }
+
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
 
        for (i = 0; i < TSC_MAX_NUM; i++) {
                struct rcar_gen3_thermal_tsc *tsc;
 
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (!res)
+                       break;
+
                tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
                if (!tsc) {
                        ret = -ENOMEM;
                        goto error_unregister;
                }
 
-               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res)
-                       break;
-
                tsc->base = devm_ioremap_resource(dev, res);
                if (IS_ERR(tsc->base)) {
                        ret = PTR_ERR(tsc->base);
@@ -297,9 +422,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                }
 
                priv->tscs[i] = tsc;
-               mutex_init(&tsc->lock);
 
-               match_data->thermal_init(tsc);
+               priv->data->thermal_init(tsc);
                rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
 
                zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
@@ -310,8 +434,23 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
                        goto error_unregister;
                }
                tsc->zone = zone;
+
+               ret = of_thermal_get_ntrips(tsc->zone);
+               if (ret < 0)
+                       goto error_unregister;
+
+               dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
        }
 
+       priv->num_tscs = i;
+
+       if (!priv->num_tscs) {
+               ret = -ENODEV;
+               goto error_unregister;
+       }
+
+       rcar_thermal_irq_set(priv, true);
+
        return 0;
 
 error_unregister:
@@ -320,9 +459,39 @@ error_unregister:
        return ret;
 }
 
+static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev)
+{
+       struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
+
+       rcar_thermal_irq_set(priv, false);
+
+       return 0;
+}
+
+static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
+{
+       struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
+       unsigned int i;
+
+       for (i = 0; i < priv->num_tscs; i++) {
+               struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
+
+               priv->data->thermal_init(tsc);
+               rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
+       }
+
+       rcar_thermal_irq_set(priv, true);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend,
+                        rcar_gen3_thermal_resume);
+
 static struct platform_driver rcar_gen3_thermal_driver = {
        .driver = {
                .name   = "rcar_gen3_thermal",
+               .pm = &rcar_gen3_thermal_pm_ops,
                .of_match_table = rcar_gen3_thermal_dt_ids,
        },
        .probe          = rcar_gen3_thermal_probe,
index 118d7d8477155fd947f3735f0fc7674815de9a23..4167373327d91a051f99d158af7bf3a6f8323669 100644 (file)
@@ -410,8 +410,6 @@ const struct ti_bandgap_data dra752_data = {
                .domain = "cpu",
                .register_cooling = ti_thermal_register_cpu_cooling,
                .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               .slope = DRA752_GRADIENT_SLOPE,
-               .constant = DRA752_GRADIENT_CONST,
                .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
                .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
                },
@@ -419,8 +417,6 @@ const struct ti_bandgap_data dra752_data = {
                .registers = &dra752_gpu_temp_sensor_registers,
                .ts_data = &dra752_gpu_temp_sensor_data,
                .domain = "gpu",
-               .slope = DRA752_GRADIENT_SLOPE,
-               .constant = DRA752_GRADIENT_CONST,
                .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
                .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
                },
@@ -428,8 +424,6 @@ const struct ti_bandgap_data dra752_data = {
                .registers = &dra752_core_temp_sensor_registers,
                .ts_data = &dra752_core_temp_sensor_data,
                .domain = "core",
-               .slope = DRA752_GRADIENT_SLOPE,
-               .constant = DRA752_GRADIENT_CONST,
                .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
                .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
                },
@@ -437,8 +431,6 @@ const struct ti_bandgap_data dra752_data = {
                .registers = &dra752_dspeve_temp_sensor_registers,
                .ts_data = &dra752_dspeve_temp_sensor_data,
                .domain = "dspeve",
-               .slope = DRA752_GRADIENT_SLOPE,
-               .constant = DRA752_GRADIENT_CONST,
                .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
                .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
                },
@@ -446,8 +438,6 @@ const struct ti_bandgap_data dra752_data = {
                .registers = &dra752_iva_temp_sensor_registers,
                .ts_data = &dra752_iva_temp_sensor_data,
                .domain = "iva",
-               .slope = DRA752_GRADIENT_SLOPE,
-               .constant = DRA752_GRADIENT_CONST,
                .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
                .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
                },
index 3ee34340edabca6de32e0e411735b56b20e0ce25..c6d217913dd1d89251b9a1a5f5bcc20724b555f6 100644 (file)
@@ -91,8 +91,6 @@ const struct ti_bandgap_data omap34xx_data = {
                .registers = &omap34xx_mpu_temp_sensor_registers,
                .ts_data = &omap34xx_mpu_temp_sensor_data,
                .domain = "cpu",
-               .slope = 0,
-               .constant = 20000,
                .slope_pcb = 0,
                .constant_pcb = 20000,
                .register_cooling = NULL,
@@ -164,8 +162,6 @@ const struct ti_bandgap_data omap36xx_data = {
                .registers = &omap36xx_mpu_temp_sensor_registers,
                .ts_data = &omap36xx_mpu_temp_sensor_data,
                .domain = "cpu",
-               .slope = 0,
-               .constant = 20000,
                .slope_pcb = 0,
                .constant_pcb = 20000,
                .register_cooling = NULL,
index d255d33da9eb328f358e3d40471a8ed2be355703..fd11133606038e40ffeb1d4c279496e3a327f5bd 100644 (file)
@@ -82,8 +82,6 @@ const struct ti_bandgap_data omap4430_data = {
                .registers = &omap4430_mpu_temp_sensor_registers,
                .ts_data = &omap4430_mpu_temp_sensor_data,
                .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4430,
-               .constant = OMAP_GRADIENT_CONST_4430,
                .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430,
                .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430,
                .register_cooling = ti_thermal_register_cpu_cooling,
@@ -222,8 +220,6 @@ const struct ti_bandgap_data omap4460_data = {
                .registers = &omap4460_mpu_temp_sensor_registers,
                .ts_data = &omap4460_mpu_temp_sensor_data,
                .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4460,
-               .constant = OMAP_GRADIENT_CONST_4460,
                .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
                .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
                .register_cooling = ti_thermal_register_cpu_cooling,
@@ -255,8 +251,6 @@ const struct ti_bandgap_data omap4470_data = {
                .registers = &omap4460_mpu_temp_sensor_registers,
                .ts_data = &omap4460_mpu_temp_sensor_data,
                .domain = "cpu",
-               .slope = OMAP_GRADIENT_SLOPE_4470,
-               .constant = OMAP_GRADIENT_CONST_4470,
                .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
                .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
                .register_cooling = ti_thermal_register_cpu_cooling,
index 79ff70c446ba195ef893125b377567ff4ac2e58b..cd9a304fb571ce7749aebad6d93606b4fce503de 100644 (file)
@@ -336,8 +336,6 @@ const struct ti_bandgap_data omap5430_data = {
                .domain = "cpu",
                .register_cooling = ti_thermal_register_cpu_cooling,
                .unregister_cooling = ti_thermal_unregister_cpu_cooling,
-               .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
-               .constant = OMAP_GRADIENT_CONST_5430_CPU,
                .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
                .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
                },
@@ -345,8 +343,6 @@ const struct ti_bandgap_data omap5430_data = {
                .registers = &omap5430_gpu_temp_sensor_registers,
                .ts_data = &omap5430_gpu_temp_sensor_data,
                .domain = "gpu",
-               .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
-               .constant = OMAP_GRADIENT_CONST_5430_GPU,
                .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
                .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
                },
index fe0adb898764901b841d31b3696c5b5c15f15cac..209c664c28235a57aec27fd0d23dbf616b9641d8 100644 (file)
@@ -254,8 +254,6 @@ struct ti_bandgap {
  * @ts_data: pointer to struct with thresholds, limits of temperature sensor
  * @registers: pointer to the list of register offsets and bitfields
  * @domain: the name of the domain where the sensor is located
- * @slope: sensor gradient slope info for hotspot extrapolation equation
- * @constant: sensor gradient const info for hotspot extrapolation equation
  * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation
  *             with no external influence
  * @constant_pcb: sensor gradient const info for hotspot extrapolation equation
@@ -274,8 +272,6 @@ struct ti_temp_sensor {
        struct temp_sensor_registers    *registers;
        char                            *domain;
        /* for hotspot extrapolation */
-       const int                       slope;
-       const int                       constant;
        const int                       slope_pcb;
        const int                       constant_pcb;
        int (*register_cooling)(struct ti_bandgap *bgp, int id);
index 0586bd0f2bab676f1c780bc1bc0499919ed5f88e..02790f69e26cec5ea5ed1a51c7993457a189e11b 100644 (file)
@@ -96,8 +96,8 @@ static inline int __ti_thermal_get_temp(void *devdata, int *temp)
                return ret;
 
        /* Default constants */
-       slope = s->slope;
-       constant = s->constant;
+       slope = thermal_zone_get_slope(data->ti_thermal);
+       constant = thermal_zone_get_offset(data->ti_thermal);
 
        pcb_tz = data->pcb_tz;
        /* In case pcb zone is available, use the extrapolation rule with it */
@@ -126,119 +126,6 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
        return __ti_thermal_get_temp(data, temp);
 }
 
-/* Bind callback functions for thermal zone */
-static int ti_thermal_bind(struct thermal_zone_device *thermal,
-                          struct thermal_cooling_device *cdev)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-       int id;
-
-       if (!data || IS_ERR(data))
-               return -ENODEV;
-
-       /* check if this is the cooling device we registered */
-       if (data->cool_dev != cdev)
-               return 0;
-
-       id = data->sensor_id;
-
-       /* Simple thing, two trips, one passive another critical */
-       return thermal_zone_bind_cooling_device(thermal, 0, cdev,
-       /* bind with min and max states defined by cpu_cooling */
-                                               THERMAL_NO_LIMIT,
-                                               THERMAL_NO_LIMIT,
-                                               THERMAL_WEIGHT_DEFAULT);
-}
-
-/* Unbind callback functions for thermal zone */
-static int ti_thermal_unbind(struct thermal_zone_device *thermal,
-                            struct thermal_cooling_device *cdev)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-
-       if (!data || IS_ERR(data))
-               return -ENODEV;
-
-       /* check if this is the cooling device we registered */
-       if (data->cool_dev != cdev)
-               return 0;
-
-       /* Simple thing, two trips, one passive another critical */
-       return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
-}
-
-/* Get mode callback functions for thermal zone */
-static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
-                              enum thermal_device_mode *mode)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-
-       if (data)
-               *mode = data->mode;
-
-       return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
-                              enum thermal_device_mode mode)
-{
-       struct ti_thermal_data *data = thermal->devdata;
-       struct ti_bandgap *bgp;
-
-       bgp = data->bgp;
-
-       if (!data->ti_thermal) {
-               dev_notice(&thermal->device, "thermal zone not registered\n");
-               return 0;
-       }
-
-       mutex_lock(&data->ti_thermal->lock);
-
-       if (mode == THERMAL_DEVICE_ENABLED)
-               data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
-       else
-               data->ti_thermal->polling_delay = 0;
-
-       mutex_unlock(&data->ti_thermal->lock);
-
-       data->mode = mode;
-       ti_bandgap_write_update_interval(bgp, data->sensor_id,
-                                       data->ti_thermal->polling_delay);
-       thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED);
-       dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
-               data->ti_thermal->polling_delay);
-
-       return 0;
-}
-
-/* Get trip type callback functions for thermal zone */
-static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
-                                   int trip, enum thermal_trip_type *type)
-{
-       if (!ti_thermal_is_valid_trip(trip))
-               return -EINVAL;
-
-       if (trip + 1 == OMAP_TRIP_NUMBER)
-               *type = THERMAL_TRIP_CRITICAL;
-       else
-               *type = THERMAL_TRIP_PASSIVE;
-
-       return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
-                                   int trip, int *temp)
-{
-       if (!ti_thermal_is_valid_trip(trip))
-               return -EINVAL;
-
-       *temp = ti_thermal_get_trip_value(trip);
-
-       return 0;
-}
-
 static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 {
        struct ti_thermal_data *data = p;
@@ -262,38 +149,11 @@ static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
        return 0;
 }
 
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-                               int trip, enum thermal_trend *trend)
-{
-       return __ti_thermal_get_trend(thermal->devdata, trip, trend);
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
-                                   int *temp)
-{
-       /* shutdown zone */
-       return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
-}
-
 static const struct thermal_zone_of_device_ops ti_of_thermal_ops = {
        .get_temp = __ti_thermal_get_temp,
        .get_trend = __ti_thermal_get_trend,
 };
 
-static struct thermal_zone_device_ops ti_thermal_ops = {
-       .get_temp = ti_thermal_get_temp,
-       .get_trend = ti_thermal_get_trend,
-       .bind = ti_thermal_bind,
-       .unbind = ti_thermal_unbind,
-       .get_mode = ti_thermal_get_mode,
-       .set_mode = ti_thermal_set_mode,
-       .get_trip_type = ti_thermal_get_trip_type,
-       .get_trip_temp = ti_thermal_get_trip_temp,
-       .get_crit_temp = ti_thermal_get_crit_temp,
-};
-
 static struct ti_thermal_data
 *ti_thermal_build_data(struct ti_bandgap *bgp, int id)
 {
@@ -331,18 +191,10 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
        data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id,
                                        data, &ti_of_thermal_ops);
        if (IS_ERR(data->ti_thermal)) {
-               /* Create thermal zone */
-               data->ti_thermal = thermal_zone_device_register(domain,
-                               OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
-                               NULL, FAST_TEMP_MONITORING_RATE,
-                               FAST_TEMP_MONITORING_RATE);
-               if (IS_ERR(data->ti_thermal)) {
-                       dev_err(bgp->dev, "thermal zone device is NULL\n");
-                       return PTR_ERR(data->ti_thermal);
-               }
-               data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
-               data->our_zone = true;
+               dev_err(bgp->dev, "thermal zone device is NULL\n");
+               return PTR_ERR(data->ti_thermal);
        }
+
        ti_bandgap_set_sensor_data(bgp, id, data);
        ti_bandgap_write_update_interval(bgp, data->sensor_id,
                                        data->ti_thermal->polling_delay);
index f8b7ffea6194f25662e5919463896ba936392861..8e85ca973967d9525f41b0747ebd0f4725d1b4dc 100644 (file)
 
 #include "ti-bandgap.h"
 
-/* sensors gradient and offsets */
-#define OMAP_GRADIENT_SLOPE_4430                               0
-#define OMAP_GRADIENT_CONST_4430                               20000
-#define OMAP_GRADIENT_SLOPE_4460                               348
-#define OMAP_GRADIENT_CONST_4460                               -9301
-#define OMAP_GRADIENT_SLOPE_4470                               308
-#define OMAP_GRADIENT_CONST_4470                               -7896
-
-#define OMAP_GRADIENT_SLOPE_5430_CPU                           65
-#define OMAP_GRADIENT_CONST_5430_CPU                           -1791
-#define OMAP_GRADIENT_SLOPE_5430_GPU                           117
-#define OMAP_GRADIENT_CONST_5430_GPU                           -2992
-
-#define DRA752_GRADIENT_SLOPE                                  0
-#define DRA752_GRADIENT_CONST                                  2000
-
 /* PCB sensor calculation constants */
 #define OMAP_GRADIENT_SLOPE_W_PCB_4430                         0
 #define OMAP_GRADIENT_CONST_W_PCB_4430                         20000