Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2017 17:54:32 +0000 (09:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Mar 2017 17:54:32 +0000 (09:54 -0800)
Pull thermal management updates from Zhang Rui:

 - add thermal driver for R-Car Gen3 thermal sensors.

 - add thermal driver for ZTE' zx2967 family thermal sensors.

 - convert thermal ID allocation from IDR to IDA.

 - fix a possible NULL dereference in imx thermal driver.

 - fix a ti-soc-thermal driver dependency issue so that critical thermal
   control is still available when CPU_THERMAL is not defined.

 - update binding information for QorIQ thermal driver.

 - a couple of cleanups in thermal core, intel_powerclamp, exynos,
   dra752-thermal, mtk-thermal driver.

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux:
  powerpc/mpc85xx: Update TMU device tree node for T1023/T1024
  powerpc/mpc85xx: Update TMU device tree node for T1040/T1042
  dt-bindings: Update QorIQ TMU thermal bindings
  thermal: mtk_thermal: Staticise a number of data variables
  thermal: arm: dra752: Remove all TSHUT related definitions
  thermal: arm: dra752: Remove TSHUT configuration
  thermal: ti-soc-thermal: Remove CPU_THERMAL Dependency from TI_THERMAL
  thermal: imx: Fix possible NULL dereference.
  thermal: exynos: Remove parsing unused samsung,tmu_cal_mode property
  thermal: zx2967: add thermal driver for ZTE's zx2967 family
  thermal: use cpumask_var_t for on-stack cpu masks
  dt: bindings: add documentation for zx2967 family thermal sensor
  thermal/intel_powerclamp: Remove set-but-not-used variables
  thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver
  thermal: rcar_gen3_thermal: Document the R-Car Gen3
  thermal: convert devfreq_cooling to use an IDA
  thermal: convert cpu_cooling to use an IDA
  thermal: convert clock cooling to use an IDA
  thermal core: convert ID allocation to IDA

22 files changed:
Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/zx2967-thermal.txt [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/t1023si-post.dtsi
arch/powerpc/boot/dts/fsl/t1040si-post.dtsi
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/clock_cooling.c
drivers/thermal/cpu_cooling.c
drivers/thermal/devfreq_cooling.c
drivers/thermal/imx_thermal.c
drivers/thermal/intel_powerclamp.c
drivers/thermal/mtk_thermal.c
drivers/thermal/rcar_gen3_thermal.c [new file with mode: 0644]
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu.h
drivers/thermal/thermal_core.c
drivers/thermal/ti-soc-thermal/Kconfig
drivers/thermal/ti-soc-thermal/dra752-bandgap.h
drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
drivers/thermal/zx2967_thermal.c [new file with mode: 0644]
include/linux/thermal.h

index 66223d561972c47a30c469230177ea8ea5bb59e9..20ca4ef9d77609a0bc0432256c70694e0ac1cbac 100644 (file)
@@ -17,6 +17,12 @@ Required properties:
        calibration data, as specified by the SoC reference manual.
        The first cell of each pair is the value to be written to TTCFGR,
        and the second is the value to be written to TSCFGR.
+- #thermal-sensor-cells : Must be 1. The sensor specifier is the monitoring
+       site ID, and represents the "n" in TRITSRn and TRATSRn.
+
+Optional property:
+- little-endian : If present, the TMU registers are little endian. If absent,
+       the default is big endian.
 
 Example:
 
@@ -60,4 +66,5 @@ tmu@f0000 {
 
                               0x00030000 0x00000012
                               0x00030001 0x0000001d>;
+       #thermal-sensor-cells = <1>;
 };
diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt
new file mode 100644 (file)
index 0000000..07a9713
--- /dev/null
@@ -0,0 +1,56 @@
+* DT bindings for Renesas R-Car Gen3 Thermal Sensor driver
+
+On R-Car Gen3 SoCs, the thermal sensor controllers (TSC) control the thermal
+sensors (THS) which are the analog circuits for measuring temperature (Tj)
+inside the LSI.
+
+Required properties:
+- compatible           : "renesas,<soctype>-thermal",
+                         Examples with soctypes are:
+                           - "renesas,r8a7795-thermal" (R-Car H3)
+                           - "renesas,r8a7796-thermal" (R-Car M3-W)
+- reg                  : Address ranges of the thermal registers. Each sensor
+                         needs one address range. Sorting must be done in
+                         increasing order according to datasheet, i.e.
+                         TSC1, TSC2, ...
+- clocks               : Must contain a reference to the functional clock.
+- #thermal-sensor-cells : must be <1>.
+
+Optional properties:
+
+- interrupts           : interrupts routed to the TSC (3 for H3 and M3-W)
+- power-domain         : Must contain a reference to the power domain. This
+                         property is mandatory if the thermal sensor instance
+                         is part of a controllable power domain.
+
+Example:
+
+       tsc: thermal@e6198000 {
+               compatible = "renesas,r8a7795-thermal";
+               reg = <0 0xe6198000 0 0x68>,
+                     <0 0xe61a0000 0 0x5c>,
+                     <0 0xe61a8000 0 0x5c>;
+               interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cpg CPG_MOD 522>;
+               power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
+               #thermal-sensor-cells = <1>;
+               status = "okay";
+       };
+
+       thermal-zones {
+               sensor_thermal1: sensor-thermal1 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+                       thermal-sensors = <&tsc 0>;
+
+                       trips {
+                               sensor1_crit: sensor1-crit {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/thermal/zx2967-thermal.txt b/Documentation/devicetree/bindings/thermal/zx2967-thermal.txt
new file mode 100644 (file)
index 0000000..3dc1c6b
--- /dev/null
@@ -0,0 +1,116 @@
+* ZTE zx2967 family Thermal
+
+Required Properties:
+- compatible: should be one of the following.
+    * zte,zx296718-thermal
+- reg: physical base address of the controller and length of memory mapped
+    region.
+- clocks : Pairs of phandle and specifier referencing the controller's clocks.
+- clock-names: "topcrm" for the topcrm clock.
+              "apb" for the apb clock.
+- #thermal-sensor-cells: must be 0.
+
+Please note: slope coefficient defined in thermal-zones section need to be
+multiplied by 1000.
+
+Example for tempsensor:
+
+       tempsensor: tempsensor@148a000 {
+               compatible = "zte,zx296718-thermal";
+               reg = <0x0148a000 0x20>;
+               clocks = <&topcrm TEMPSENSOR_GATE>, <&audiocrm AUDIO_TS_PCLK>;
+               clock-names = "topcrm", "apb";
+               #thermal-sensor-cells = <0>;
+       };
+
+Example for cooling device:
+
+       cooling_dev: cooling_dev {
+               cluster0_cooling_dev: cluster0-cooling-dev {
+                       #cooling-cells = <2>;
+                       cpumask = <0xf>;
+                       capacitance = <1500>;
+               };
+
+       cluster1_cooling_dev: cluster1-cooling-dev {
+                       #cooling-cells = <2>;
+                       cpumask = <0x30>;
+                       capacitance = <2000>;
+               };
+       };
+
+Example for thermal zones:
+
+       thermal-zones {
+               zx296718_thermal: zx296718_thermal {
+                       polling-delay-passive = <500>;
+                       polling-delay = <1000>;
+                       sustainable-power = <6500>;
+
+                       thermal-sensors = <&tempsensor 0>;
+                       /*
+                        * slope need to be multiplied by 1000.
+                        */
+                       coefficients = <1951 (-922)>;
+
+                       trips {
+                               trip0: switch_on_temperature {
+                                       temperature = <90000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               trip1: desired_temperature {
+                                       temperature = <100000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+
+                               crit: critical_temperature {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+
+                       cooling-maps {
+                               map0 {
+                                       trip = <&trip0>;
+                                       cooling-device = <&gpu 2 5>;
+                               };
+
+                               map1 {
+                                       trip = <&trip0>;
+                                       cooling-device = <&cluster0_cooling_dev 1 2>;
+                               };
+
+                               map2 {
+                                       trip = <&trip1>;
+                                       cooling-device = <&cluster0_cooling_dev 1 2>;
+                               };
+
+                               map3 {
+                                       trip = <&crit>;
+                                       cooling-device = <&cluster0_cooling_dev 1 2>;
+                               };
+
+                               map4 {
+                                       trip = <&trip0>;
+                                       cooling-device = <&cluster1_cooling_dev 1 2>;
+                                       contribution = <9000>;
+                               };
+
+                               map5 {
+                                       trip = <&trip1>;
+                                       cooling-device = <&cluster1_cooling_dev 1 2>;
+                                       contribution = <4096>;
+                               };
+
+                               map6 {
+                                       trip = <&crit>;
+                                       cooling-device = <&cluster1_cooling_dev 1 2>;
+                                       contribution = <4096>;
+                               };
+                       };
+               };
+       };
index da2894c594790e347b4126cd8fc6d95842cd9a70..4908af5010983c2af7df21020d18a9e9c2e2ffb7 100644 (file)
                                       0x00030001 0x0000000d
                                       0x00030002 0x00000019
                                       0x00030003 0x00000024>;
-               #thermal-sensor-cells = <0>;
+               #thermal-sensor-cells = <1>;
        };
 
        thermal-zones {
                        polling-delay-passive = <1000>;
                        polling-delay = <5000>;
 
-                       thermal-sensors = <&tmu>;
+                       thermal-sensors = <&tmu 0>;
 
                        trips {
                                cpu_alert: cpu-alert {
index 44e399b17f6fc99fd489920e097217a32082f501..145c7f43b5b6011874092180d300767bdfc2b82c 100644 (file)
 
                                       0x00030000 0x00000012
                                       0x00030001 0x0000001d>;
-               #thermal-sensor-cells = <0>;
+               #thermal-sensor-cells = <1>;
        };
 
        thermal-zones {
                        polling-delay-passive = <1000>;
                        polling-delay = <5000>;
 
-                       thermal-sensors = <&tmu>;
+                       thermal-sensors = <&tmu 2>;
 
                        trips {
                                cpu_alert: cpu-alert {
index c2c056cc7ea52e1a7170b35de2832c1b1dcf40b4..776b34396144a4612ec5ebfff5a549be9f6e33ca 100644 (file)
@@ -245,6 +245,15 @@ config RCAR_THERMAL
          Enable this to plug the R-Car thermal sensor driver into the Linux
          thermal framework.
 
+config RCAR_GEN3_THERMAL
+       tristate "Renesas R-Car Gen3 thermal driver"
+       depends on ARCH_RENESAS || COMPILE_TEST
+       depends on HAS_IOMEM
+       depends on OF
+       help
+         Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux
+         thermal framework.
+
 config KIRKWOOD_THERMAL
        tristate "Temperature sensor on Marvell Kirkwood SoCs"
        depends on MACH_KIRKWOOD || COMPILE_TEST
@@ -436,4 +445,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
 source "drivers/thermal/qcom/Kconfig"
 endmenu
 
+config ZX2967_THERMAL
+       tristate "Thermal sensors on zx2967 SoC"
+       depends on ARCH_ZX || COMPILE_TEST
+       help
+         Enable the zx2967 thermal sensors driver, which supports
+         the primitive temperature sensor embedded in zx2967 SoCs.
+         This sensor generates the real time die temperature.
+
 endif
index 6a3d7b57303655f58b7fec456cc43519fa29dc91..7adae2029355639b03359fb542c6030f93808ab5 100644 (file)
@@ -31,6 +31,7 @@ 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
 obj-$(CONFIG_RCAR_THERMAL)     += rcar_thermal.o
+obj-$(CONFIG_RCAR_GEN3_THERMAL)        += rcar_gen3_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y                          += samsung/
 obj-$(CONFIG_DOVE_THERMAL)     += dove_thermal.o
@@ -56,3 +57,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM)  += tegra/
 obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
 obj-$(CONFIG_MTK_THERMAL)      += mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)      += thermal-generic-adc.o
+obj-$(CONFIG_ZX2967_THERMAL)   += zx2967_thermal.o
index ed5dd0e8865746fe928f08459218779b97227103..56711c25584dd06004e2046a8d7c56f49b420a85 100644 (file)
@@ -65,42 +65,7 @@ struct clock_cooling_device {
 };
 #define to_clock_cooling_device(x) \
                container_of(x, struct clock_cooling_device, clk_rate_change_nb)
-static DEFINE_IDR(clock_idr);
-static DEFINE_MUTEX(cooling_clock_lock);
-
-/**
- * clock_cooling_get_idr - function to get an unique id.
- * @id: int * value generated by this function.
- *
- * This function will populate @id with an unique
- * id, using the idr API.
- *
- * Return: 0 on success, an error code on failure.
- */
-static int clock_cooling_get_idr(int *id)
-{
-       int ret;
-
-       mutex_lock(&cooling_clock_lock);
-       ret = idr_alloc(&clock_idr, NULL, 0, 0, GFP_KERNEL);
-       mutex_unlock(&cooling_clock_lock);
-       if (unlikely(ret < 0))
-               return ret;
-       *id = ret;
-
-       return 0;
-}
-
-/**
- * release_idr - function to free the unique id.
- * @id: int value representing the unique id.
- */
-static void release_idr(int id)
-{
-       mutex_lock(&cooling_clock_lock);
-       idr_remove(&clock_idr, id);
-       mutex_unlock(&cooling_clock_lock);
-}
+static DEFINE_IDA(clock_ida);
 
 /* Below code defines functions to be used for clock as cooling device */
 
@@ -432,16 +397,17 @@ clock_cooling_register(struct device *dev, const char *clock_name)
        if (IS_ERR(ccdev->clk))
                return ERR_CAST(ccdev->clk);
 
-       ret = clock_cooling_get_idr(&ccdev->id);
-       if (ret)
-               return ERR_PTR(-EINVAL);
+       ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       ccdev->id = ret;
 
        snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
 
        cdev = thermal_cooling_device_register(dev_name, ccdev,
                                               &clock_cooling_ops);
        if (IS_ERR(cdev)) {
-               release_idr(ccdev->id);
+               ida_simple_remove(&clock_ida, ccdev->id);
                return ERR_PTR(-EINVAL);
        }
        ccdev->cdev = cdev;
@@ -450,7 +416,7 @@ clock_cooling_register(struct device *dev, const char *clock_name)
        /* Assuming someone has already filled the opp table for this device */
        ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
        if (ret) {
-               release_idr(ccdev->id);
+               ida_simple_remove(&clock_ida, ccdev->id);
                return ERR_PTR(ret);
        }
        ccdev->clock_state = 0;
@@ -481,6 +447,6 @@ void clock_cooling_unregister(struct thermal_cooling_device *cdev)
        dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
 
        thermal_cooling_device_unregister(ccdev->cdev);
-       release_idr(ccdev->id);
+       ida_simple_remove(&clock_ida, ccdev->id);
 }
 EXPORT_SYMBOL_GPL(clock_cooling_unregister);
index 85fdbf762fa02ac4d70ed231a603afe23bb5013d..91048eeca28b2dc3d81f234ed60bbfdd796f8277 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/thermal.h>
 #include <linux/cpufreq.h>
 #include <linux/err.h>
+#include <linux/idr.h>
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
@@ -104,50 +105,13 @@ struct cpufreq_cooling_device {
        struct device *cpu_dev;
        get_static_t plat_get_static_power;
 };
-static DEFINE_IDR(cpufreq_idr);
-static DEFINE_MUTEX(cooling_cpufreq_lock);
+static DEFINE_IDA(cpufreq_ida);
 
 static unsigned int cpufreq_dev_count;
 
 static DEFINE_MUTEX(cooling_list_lock);
 static LIST_HEAD(cpufreq_dev_list);
 
-/**
- * get_idr - function to get a unique id.
- * @idr: struct idr * handle used to create a id.
- * @id: int * value generated by this function.
- *
- * This function will populate @id with an unique
- * id, using the idr API.
- *
- * Return: 0 on success, an error code on failure.
- */
-static int get_idr(struct idr *idr, int *id)
-{
-       int ret;
-
-       mutex_lock(&cooling_cpufreq_lock);
-       ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
-       mutex_unlock(&cooling_cpufreq_lock);
-       if (unlikely(ret < 0))
-               return ret;
-       *id = ret;
-
-       return 0;
-}
-
-/**
- * release_idr - function to free the unique id.
- * @idr: struct idr * handle used for creating the id.
- * @id: int value representing the unique id.
- */
-static void release_idr(struct idr *idr, int id)
-{
-       mutex_lock(&cooling_cpufreq_lock);
-       idr_remove(idr, id);
-       mutex_unlock(&cooling_cpufreq_lock);
-}
-
 /* Below code defines functions to be used for cpufreq as cooling device */
 
 /**
@@ -645,31 +609,39 @@ static int cpufreq_state2power(struct thermal_cooling_device *cdev,
                               unsigned long state, u32 *power)
 {
        unsigned int freq, num_cpus;
-       cpumask_t cpumask;
+       cpumask_var_t cpumask;
        u32 static_power, dynamic_power;
        int ret;
        struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 
-       cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
-       num_cpus = cpumask_weight(&cpumask);
+       if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
+               return -ENOMEM;
+
+       cpumask_and(cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask);
+       num_cpus = cpumask_weight(cpumask);
 
        /* None of our cpus are online, so no power */
        if (num_cpus == 0) {
                *power = 0;
-               return 0;
+               ret = 0;
+               goto out;
        }
 
        freq = cpufreq_device->freq_table[state];
-       if (!freq)
-               return -EINVAL;
+       if (!freq) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus;
        ret = get_static_power(cpufreq_device, tz, freq, &static_power);
        if (ret)
-               return ret;
+               goto out;
 
        *power = static_power + dynamic_power;
-       return 0;
+out:
+       free_cpumask_var(cpumask);
+       return ret;
 }
 
 /**
@@ -795,16 +767,20 @@ __cpufreq_cooling_register(struct device_node *np,
        struct cpufreq_cooling_device *cpufreq_dev;
        char dev_name[THERMAL_NAME_LENGTH];
        struct cpufreq_frequency_table *pos, *table;
-       struct cpumask temp_mask;
+       cpumask_var_t temp_mask;
        unsigned int freq, i, num_cpus;
        int ret;
        struct thermal_cooling_device_ops *cooling_ops;
 
-       cpumask_and(&temp_mask, clip_cpus, cpu_online_mask);
-       policy = cpufreq_cpu_get(cpumask_first(&temp_mask));
+       if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
+               return ERR_PTR(-ENOMEM);
+
+       cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
+       policy = cpufreq_cpu_get(cpumask_first(temp_mask));
        if (!policy) {
                pr_debug("%s: CPUFreq policy not found\n", __func__);
-               return ERR_PTR(-EPROBE_DEFER);
+               cool_dev = ERR_PTR(-EPROBE_DEFER);
+               goto free_cpumask;
        }
 
        table = policy->freq_table;
@@ -867,11 +843,12 @@ __cpufreq_cooling_register(struct device_node *np,
                cooling_ops = &cpufreq_cooling_ops;
        }
 
-       ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
-       if (ret) {
+       ret = ida_simple_get(&cpufreq_ida, 0, 0, GFP_KERNEL);
+       if (ret < 0) {
                cool_dev = ERR_PTR(ret);
                goto free_power_table;
        }
+       cpufreq_dev->id = ret;
 
        /* Fill freq-table in descending order of frequencies */
        for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
@@ -891,27 +868,24 @@ __cpufreq_cooling_register(struct device_node *np,
        cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
                                                      cooling_ops);
        if (IS_ERR(cool_dev))
-               goto remove_idr;
+               goto remove_ida;
 
        cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
        cpufreq_dev->cool_dev = cool_dev;
 
-       mutex_lock(&cooling_cpufreq_lock);
-
        mutex_lock(&cooling_list_lock);
        list_add(&cpufreq_dev->node, &cpufreq_dev_list);
-       mutex_unlock(&cooling_list_lock);
 
        /* Register the notifier for first cpufreq cooling device */
        if (!cpufreq_dev_count++)
                cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
                                          CPUFREQ_POLICY_NOTIFIER);
-       mutex_unlock(&cooling_cpufreq_lock);
+       mutex_unlock(&cooling_list_lock);
 
        goto put_policy;
 
-remove_idr:
-       release_idr(&cpufreq_idr, cpufreq_dev->id);
+remove_ida:
+       ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
 free_power_table:
        kfree(cpufreq_dev->dyn_power_table);
 free_table:
@@ -924,7 +898,8 @@ free_cdev:
        kfree(cpufreq_dev);
 put_policy:
        cpufreq_cpu_put(policy);
-
+free_cpumask:
+       free_cpumask_var(temp_mask);
        return cool_dev;
 }
 
@@ -1052,20 +1027,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 
        cpufreq_dev = cdev->devdata;
 
+       mutex_lock(&cooling_list_lock);
        /* Unregister the notifier for the last cpufreq cooling device */
-       mutex_lock(&cooling_cpufreq_lock);
        if (!--cpufreq_dev_count)
                cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
                                            CPUFREQ_POLICY_NOTIFIER);
 
-       mutex_lock(&cooling_list_lock);
        list_del(&cpufreq_dev->node);
        mutex_unlock(&cooling_list_lock);
 
-       mutex_unlock(&cooling_cpufreq_lock);
-
        thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
-       release_idr(&cpufreq_idr, cpufreq_dev->id);
+       ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
        kfree(cpufreq_dev->dyn_power_table);
        kfree(cpufreq_dev->time_in_idle_timestamp);
        kfree(cpufreq_dev->time_in_idle);
index ba7a5cd994dc9229351bd4ee057941afabcab8fc..7743a78d472397bbf9a10c0b1ac2d7e4b163a6a6 100644 (file)
 #include <linux/devfreq.h>
 #include <linux/devfreq_cooling.h>
 #include <linux/export.h>
+#include <linux/idr.h>
 #include <linux/slab.h>
 #include <linux/pm_opp.h>
 #include <linux/thermal.h>
 
 #include <trace/events/thermal.h>
 
-static DEFINE_MUTEX(devfreq_lock);
-static DEFINE_IDR(devfreq_idr);
+static DEFINE_IDA(devfreq_ida);
 
 /**
  * struct devfreq_cooling_device - Devfreq cooling device
@@ -57,42 +57,6 @@ struct devfreq_cooling_device {
        struct devfreq_cooling_power *power_ops;
 };
 
-/**
- * get_idr - function to get a unique id.
- * @idr: struct idr * handle used to create a id.
- * @id: int * value generated by this function.
- *
- * This function will populate @id with an unique
- * id, using the idr API.
- *
- * Return: 0 on success, an error code on failure.
- */
-static int get_idr(struct idr *idr, int *id)
-{
-       int ret;
-
-       mutex_lock(&devfreq_lock);
-       ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
-       mutex_unlock(&devfreq_lock);
-       if (unlikely(ret < 0))
-               return ret;
-       *id = ret;
-
-       return 0;
-}
-
-/**
- * release_idr - function to free the unique id.
- * @idr: struct idr * handle used for creating the id.
- * @id: int value representing the unique id.
- */
-static void release_idr(struct idr *idr, int id)
-{
-       mutex_lock(&devfreq_lock);
-       idr_remove(idr, id);
-       mutex_unlock(&devfreq_lock);
-}
-
 /**
  * partition_enable_opps() - disable all opps above a given state
  * @dfc:       Pointer to devfreq we are operating on
@@ -489,9 +453,10 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
        if (err)
                goto free_dfc;
 
-       err = get_idr(&devfreq_idr, &dfc->id);
-       if (err)
+       err = ida_simple_get(&devfreq_ida, 0, 0, GFP_KERNEL);
+       if (err < 0)
                goto free_tables;
+       dfc->id = err;
 
        snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
 
@@ -502,15 +467,15 @@ of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
                dev_err(df->dev.parent,
                        "Failed to register devfreq cooling device (%d)\n",
                        err);
-               goto release_idr;
+               goto release_ida;
        }
 
        dfc->cdev = cdev;
 
        return cdev;
 
-release_idr:
-       release_idr(&devfreq_idr, dfc->id);
+release_ida:
+       ida_simple_remove(&devfreq_ida, dfc->id);
 free_tables:
        kfree(dfc->power_table);
        kfree(dfc->freq_table);
@@ -558,7 +523,7 @@ void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
        dfc = cdev->devdata;
 
        thermal_cooling_device_unregister(dfc->cdev);
-       release_idr(&devfreq_idr, dfc->id);
+       ida_simple_remove(&devfreq_ida, dfc->id);
        kfree(dfc->power_table);
        kfree(dfc->freq_table);
 
index 06912f0602b75ba1a7d801babc686f5305838b59..fb648a45754eeff4177b0257b657ed59c4fe7a10 100644 (file)
@@ -489,6 +489,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
        data->tempmon = map;
 
        data->socdata = of_device_get_match_data(&pdev->dev);
+       if (!data->socdata) {
+               dev_err(&pdev->dev, "no device match found\n");
+               return -ENODEV;
+       }
 
        /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
        if (data->socdata->version == TEMPMON_IMX6SX) {
index df64692e9e64a22edf2d43f8b2e6a1f4b01f931b..a47103a659fa4d5bf11883c603a03787e7a548aa 100644 (file)
@@ -461,16 +461,13 @@ static void poll_pkg_cstate(struct work_struct *dummy)
 {
        static u64 msr_last;
        static u64 tsc_last;
-       static unsigned long jiffies_last;
 
        u64 msr_now;
-       unsigned long jiffies_now;
        u64 tsc_now;
        u64 val64;
 
        msr_now = pkg_state_counter();
        tsc_now = rdtsc();
-       jiffies_now = jiffies;
 
        /* calculate pkg cstate vs tsc ratio */
        if (!msr_last || !tsc_last)
@@ -485,7 +482,6 @@ static void poll_pkg_cstate(struct work_struct *dummy)
 
        /* update record */
        msr_last = msr_now;
-       jiffies_last = jiffies_now;
        tsc_last = tsc_now;
 
        if (true == clamping)
index 34169c32d4956ffe8bb146ab0ae66a8f4ebbdbf2..1aff7fde54b18f217232f0c74cbf3787f55670e0 100644 (file)
@@ -183,37 +183,37 @@ struct mtk_thermal {
 };
 
 /* MT8173 thermal sensor data */
-const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
+static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
        { MT8173_TS2, MT8173_TS3 },
        { MT8173_TS2, MT8173_TS4 },
        { MT8173_TS1, MT8173_TS2, MT8173_TSABB },
        { MT8173_TS2 },
 };
 
-const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
+static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
        TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2
 };
 
-const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
+static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
        TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
 };
 
-const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
+static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
 
 /* MT2701 thermal sensor data */
-const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
+static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
        MT2701_TS1, MT2701_TS2, MT2701_TSABB
 };
 
-const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
+static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
        TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
 };
 
-const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
+static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
        TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
 };
 
-const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
+static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
 
 /**
  * The MT8173 thermal controller has four banks. Each bank can read up to
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
new file mode 100644 (file)
index 0000000..d33c845
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *  R-Car Gen3 THS thermal sensor driver
+ *  Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation.
+ * Copyright (C) 2016 Sang Engineering
+ *
+ *  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; version 2 of the License.
+ *
+ *  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/delay.h>
+#include <linux/err.h>
+#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/thermal.h>
+
+/* Register offsets */
+#define REG_GEN3_IRQSTR                0x04
+#define REG_GEN3_IRQMSK                0x08
+#define REG_GEN3_IRQCTL                0x0C
+#define REG_GEN3_IRQEN         0x10
+#define REG_GEN3_IRQTEMP1      0x14
+#define REG_GEN3_IRQTEMP2      0x18
+#define REG_GEN3_IRQTEMP3      0x1C
+#define REG_GEN3_CTSR          0x20
+#define REG_GEN3_THCTR         0x20
+#define REG_GEN3_TEMP          0x28
+#define REG_GEN3_THCODE1       0x50
+#define REG_GEN3_THCODE2       0x54
+#define REG_GEN3_THCODE3       0x58
+
+/* CTSR bits */
+#define CTSR_PONM      BIT(8)
+#define CTSR_AOUT      BIT(7)
+#define CTSR_THBGR     BIT(5)
+#define CTSR_VMEN      BIT(4)
+#define CTSR_VMST      BIT(1)
+#define CTSR_THSST     BIT(0)
+
+/* THCTR bits */
+#define THCTR_PONM     BIT(6)
+#define THCTR_THSST    BIT(0)
+
+#define CTEMP_MASK     0xFFF
+
+#define MCELSIUS(temp) ((temp) * 1000)
+#define GEN3_FUSE_MASK 0xFFF
+
+#define TSC_MAX_NUM    3
+
+/* Structure for thermal temperature calculation */
+struct equation_coefs {
+       int a1;
+       int b1;
+       int a2;
+       int b2;
+};
+
+struct rcar_gen3_thermal_tsc {
+       void __iomem *base;
+       struct thermal_zone_device *zone;
+       struct equation_coefs coef;
+       struct mutex lock;
+};
+
+struct rcar_gen3_thermal_priv {
+       struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
+};
+
+struct rcar_gen3_thermal_data {
+       void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
+};
+
+static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
+                                        u32 reg)
+{
+       return ioread32(tsc->base + reg);
+}
+
+static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
+                                          u32 reg, u32 data)
+{
+       iowrite32(data, tsc->base + reg);
+}
+
+/*
+ * Linear approximation for temperature
+ *
+ * [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
+ *
+ * The constants a and b are calculated using two triplets of int values PTAT
+ * and THCODE. PTAT and THCODE can either be read from hardware or use hard
+ * coded values from driver. The formula to calculate a and b are taken from
+ * BSP and sparsely documented and understood.
+ *
+ * Examining the linear formula and the formula used to calculate constants a
+ * and b while knowing that the span for PTAT and THCODE values are between
+ * 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
+ * Integer also needs to be signed so that leaves 7 bits for binary
+ * fixed point scaling.
+ */
+
+#define FIXPT_SHIFT 7
+#define FIXPT_INT(_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)
+
+#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
+
+/* no idea where these constants come from */
+#define TJ_1 96
+#define TJ_3 -41
+
+static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
+                                        int *ptat, int *thcode)
+{
+       int tj_2;
+
+       /* TODO: Find documentation and document constant calculation formula */
+
+       /*
+        * Division is not scaled in BSP and if scaled it might overflow
+        * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
+        */
+       tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137)
+               / (ptat[0] - ptat[2])) - FIXPT_INT(41);
+
+       coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
+                            tj_2 - FIXPT_INT(TJ_3));
+       coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3;
+
+       coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
+                            tj_2 - FIXPT_INT(TJ_1));
+       coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1;
+}
+
+static int rcar_gen3_thermal_round(int temp)
+{
+       int result, round_offs;
+
+       round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
+               -RCAR3_THERMAL_GRAN / 2;
+       result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
+       return result * RCAR3_THERMAL_GRAN;
+}
+
+static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
+{
+       struct rcar_gen3_thermal_tsc *tsc = devdata;
+       int mcelsius, val1, val2;
+       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;
+
+       /* Round value to device granularity setting */
+       *temp = rcar_gen3_thermal_round(mcelsius);
+
+       return 0;
+}
+
+static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
+       .get_temp       = rcar_gen3_thermal_get_temp,
+};
+
+static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
+{
+       rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  CTSR_THBGR);
+       rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  0x0);
+
+       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_CTSR,
+                               CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
+
+       usleep_range(100, 200);
+
+       rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
+                               CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
+                               CTSR_VMST | CTSR_THSST);
+
+       usleep_range(1000, 2000);
+}
+
+static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
+{
+       u32 reg_val;
+
+       reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
+       reg_val &= ~THCTR_PONM;
+       rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
+
+       usleep_range(1000, 2000);
+
+       rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
+       reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
+       reg_val |= THCTR_THSST;
+       rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
+}
+
+static const struct rcar_gen3_thermal_data r8a7795_data = {
+       .thermal_init = r8a7795_thermal_init,
+};
+
+static const struct rcar_gen3_thermal_data r8a7796_data = {
+       .thermal_init = r8a7796_thermal_init,
+};
+
+static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
+       { .compatible = "renesas,r8a7795-thermal", .data = &r8a7795_data},
+       { .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
+       {},
+};
+MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
+
+static int rcar_gen3_thermal_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+
+       return 0;
+}
+
+static int rcar_gen3_thermal_probe(struct platform_device *pdev)
+{
+       struct rcar_gen3_thermal_priv *priv;
+       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);
+
+       /* default values if FUSEs are missing */
+       /* TODO: Read values from hardware on supported platforms */
+       int ptat[3] = { 2351, 1509, 435 };
+       int thcode[TSC_MAX_NUM][3] = {
+               { 3248, 2800, 2221 },
+               { 3245, 2795, 2216 },
+               { 3250, 2805, 2237 },
+       };
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+
+       for (i = 0; i < TSC_MAX_NUM; i++) {
+               struct rcar_gen3_thermal_tsc *tsc;
+
+               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);
+                       goto error_unregister;
+               }
+
+               priv->tscs[i] = tsc;
+               mutex_init(&tsc->lock);
+
+               match_data->thermal_init(tsc);
+               rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
+
+               zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
+                                                           &rcar_gen3_tz_of_ops);
+               if (IS_ERR(zone)) {
+                       dev_err(dev, "Can't register thermal zone\n");
+                       ret = PTR_ERR(zone);
+                       goto error_unregister;
+               }
+               tsc->zone = zone;
+       }
+
+       return 0;
+
+error_unregister:
+       rcar_gen3_thermal_remove(pdev);
+
+       return ret;
+}
+
+static struct platform_driver rcar_gen3_thermal_driver = {
+       .driver = {
+               .name   = "rcar_gen3_thermal",
+               .of_match_table = rcar_gen3_thermal_dt_ids,
+       },
+       .probe          = rcar_gen3_thermal_probe,
+       .remove         = rcar_gen3_thermal_remove,
+};
+module_platform_driver(rcar_gen3_thermal_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
+MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
index ad1186dd6132c3ca74f7df209605a25745b16cac..7b8ef09d2b3cfda5fc48b18c9a84965d15a00cc9 100644 (file)
@@ -1168,7 +1168,6 @@ static int exynos_of_sensor_conf(struct device_node *np,
        pdata->default_temp_offset = (u8)value;
 
        of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
-       of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
 
        of_node_put(np);
        return 0;
index 440c7140b6603f8b20e493b448cd42a403e76708..5149c2a3030c954dd6b2a3380a911ec551faea55 100644 (file)
@@ -70,7 +70,6 @@ struct exynos_tmu_platform_data {
 
        enum soc_type type;
        u32 cal_type;
-       u32 cal_mode;
 };
 
 #endif /* _EXYNOS_TMU_H */
index 655591316a881274a6d152801ffd19138a0dc34b..11f0675cb7e552456d36ec49c82a46d5cf016d04 100644 (file)
@@ -36,9 +36,8 @@ MODULE_AUTHOR("Zhang Rui");
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL v2");
 
-static DEFINE_IDR(thermal_tz_idr);
-static DEFINE_IDR(thermal_cdev_idr);
-static DEFINE_MUTEX(thermal_idr_lock);
+static DEFINE_IDA(thermal_tz_ida);
+static DEFINE_IDA(thermal_cdev_ida);
 
 static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_cdev_list);
@@ -589,29 +588,6 @@ void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz,
  * - thermal zone devices lifecycle: registration, unregistration,
  *                                  binding, and unbinding.
  */
-static int get_idr(struct idr *idr, struct mutex *lock, int *id)
-{
-       int ret;
-
-       if (lock)
-               mutex_lock(lock);
-       ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
-       if (lock)
-               mutex_unlock(lock);
-       if (unlikely(ret < 0))
-               return ret;
-       *id = ret;
-       return 0;
-}
-
-static void release_idr(struct idr *idr, struct mutex *lock, int id)
-{
-       if (lock)
-               mutex_lock(lock);
-       idr_remove(idr, id);
-       if (lock)
-               mutex_unlock(lock);
-}
 
 /**
  * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
@@ -685,15 +661,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        dev->target = THERMAL_NO_TARGET;
        dev->weight = weight;
 
-       result = get_idr(&tz->idr, &tz->lock, &dev->id);
-       if (result)
+       result = ida_simple_get(&tz->ida, 0, 0, GFP_KERNEL);
+       if (result < 0)
                goto free_mem;
 
+       dev->id = result;
        sprintf(dev->name, "cdev%d", dev->id);
        result =
            sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
        if (result)
-               goto release_idr;
+               goto release_ida;
 
        sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
        sysfs_attr_init(&dev->attr.attr);
@@ -737,8 +714,8 @@ remove_trip_file:
        device_remove_file(&tz->device, &dev->attr);
 remove_symbol_link:
        sysfs_remove_link(&tz->device.kobj, dev->name);
-release_idr:
-       release_idr(&tz->idr, &tz->lock, dev->id);
+release_ida:
+       ida_simple_remove(&tz->ida, dev->id);
 free_mem:
        kfree(dev);
        return result;
@@ -785,7 +762,7 @@ unbind:
        device_remove_file(&tz->device, &pos->weight_attr);
        device_remove_file(&tz->device, &pos->attr);
        sysfs_remove_link(&tz->device.kobj, pos->name);
-       release_idr(&tz->idr, &tz->lock, pos->id);
+       ida_simple_remove(&tz->ida, pos->id);
        kfree(pos);
        return 0;
 }
@@ -925,12 +902,13 @@ __thermal_cooling_device_register(struct device_node *np,
        if (!cdev)
                return ERR_PTR(-ENOMEM);
 
-       result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
-       if (result) {
+       result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
+       if (result < 0) {
                kfree(cdev);
                return ERR_PTR(result);
        }
 
+       cdev->id = result;
        strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
        mutex_init(&cdev->lock);
        INIT_LIST_HEAD(&cdev->thermal_instances);
@@ -943,7 +921,7 @@ __thermal_cooling_device_register(struct device_node *np,
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        result = device_register(&cdev->device);
        if (result) {
-               release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+               ida_simple_remove(&thermal_cdev_ida, cdev->id);
                kfree(cdev);
                return ERR_PTR(result);
        }
@@ -1070,7 +1048,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
        mutex_unlock(&thermal_list_lock);
 
-       release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+       ida_simple_remove(&thermal_cdev_ida, cdev->id);
        device_unregister(&cdev->device);
 }
 EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
@@ -1172,14 +1150,15 @@ thermal_zone_device_register(const char *type, int trips, int mask,
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&tz->thermal_instances);
-       idr_init(&tz->idr);
+       ida_init(&tz->ida);
        mutex_init(&tz->lock);
-       result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
-       if (result) {
+       result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);
+       if (result < 0) {
                kfree(tz);
                return ERR_PTR(result);
        }
 
+       tz->id = result;
        strlcpy(tz->type, type, sizeof(tz->type));
        tz->ops = ops;
        tz->tzp = tzp;
@@ -1201,7 +1180,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        dev_set_name(&tz->device, "thermal_zone%d", tz->id);
        result = device_register(&tz->device);
        if (result) {
-               release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+               ida_simple_remove(&thermal_tz_ida, tz->id);
                kfree(tz);
                return ERR_PTR(result);
        }
@@ -1255,7 +1234,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
        return tz;
 
 unregister:
-       release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+       ida_simple_remove(&thermal_tz_ida, tz->id);
        device_unregister(&tz->device);
        return ERR_PTR(result);
 }
@@ -1313,8 +1292,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
        thermal_set_governor(tz, NULL);
 
        thermal_remove_hwmon_sysfs(tz);
-       release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
-       idr_destroy(&tz->idr);
+       ida_simple_remove(&thermal_tz_ida, tz->id);
+       ida_destroy(&tz->ida);
        mutex_destroy(&tz->lock);
        device_unregister(&tz->device);
 }
@@ -1514,9 +1493,8 @@ unregister_class:
 unregister_governors:
        thermal_unregister_governors();
 error:
-       idr_destroy(&thermal_tz_idr);
-       idr_destroy(&thermal_cdev_idr);
-       mutex_destroy(&thermal_idr_lock);
+       ida_destroy(&thermal_tz_ida);
+       ida_destroy(&thermal_cdev_ida);
        mutex_destroy(&thermal_list_lock);
        mutex_destroy(&thermal_governor_lock);
        return result;
@@ -1529,9 +1507,8 @@ static void __exit thermal_exit(void)
        genetlink_exit();
        class_unregister(&thermal_class);
        thermal_unregister_governors();
-       idr_destroy(&thermal_tz_idr);
-       idr_destroy(&thermal_cdev_idr);
-       mutex_destroy(&thermal_idr_lock);
+       ida_destroy(&thermal_tz_ida);
+       ida_destroy(&thermal_cdev_ida);
        mutex_destroy(&thermal_list_lock);
        mutex_destroy(&thermal_governor_lock);
 }
index ea8283f08aa68020cf3f7e5c7e7927d2be5b8b84..fe0e877f84d014c18db574ff332721b5b8e54ce3 100644 (file)
@@ -11,7 +11,6 @@ config TI_SOC_THERMAL
 config TI_THERMAL
        bool "Texas Instruments SoCs thermal framework support"
        depends on TI_SOC_THERMAL
-       depends on CPU_THERMAL
        help
          If you say yes here you want to get support for generic thermal
          framework for the Texas Instruments on die bandgap temperature sensor.
index 6b0f2b1160f76b01de7d4d9e9fc318bf52ef34ee..a31e4b5e82cd9765330ea49a983bfb5048c90965 100644 (file)
@@ -54,7 +54,6 @@
 #define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET           0x8
 #define DRA752_TEMP_SENSOR_CORE_OFFSET                 0x154
 #define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET           0x1ac
-#define DRA752_BANDGAP_TSHUT_CORE_OFFSET               0x1b8
 #define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET         0x1c4
 #define DRA752_DTEMP_CORE_0_OFFSET                     0x208
 #define DRA752_DTEMP_CORE_1_OFFSET                     0x20c
@@ -66,7 +65,6 @@
 #define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET            0x388
 #define DRA752_TEMP_SENSOR_IVA_OFFSET                  0x398
 #define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET            0x3a4
-#define DRA752_BANDGAP_TSHUT_IVA_OFFSET                        0x3ac
 #define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET          0x3b4
 #define DRA752_DTEMP_IVA_0_OFFSET                      0x3d0
 #define DRA752_DTEMP_IVA_1_OFFSET                      0x3d4
@@ -78,7 +76,6 @@
 #define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET            0x4
 #define DRA752_TEMP_SENSOR_MPU_OFFSET                  0x14c
 #define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET            0x1a4
-#define DRA752_BANDGAP_TSHUT_MPU_OFFSET                        0x1b0
 #define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET          0x1bc
 #define DRA752_DTEMP_MPU_0_OFFSET                      0x1e0
 #define DRA752_DTEMP_MPU_1_OFFSET                      0x1e4
@@ -90,7 +87,6 @@
 #define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET                 0x384
 #define DRA752_TEMP_SENSOR_DSPEVE_OFFSET                       0x394
 #define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET                 0x3a0
-#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET                     0x3a8
 #define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET               0x3b0
 #define DRA752_DTEMP_DSPEVE_0_OFFSET                           0x3bc
 #define DRA752_DTEMP_DSPEVE_1_OFFSET                           0x3c0
 #define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET            0x0
 #define DRA752_TEMP_SENSOR_GPU_OFFSET                  0x150
 #define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET            0x1a8
-#define DRA752_BANDGAP_TSHUT_GPU_OFFSET                        0x1b4
 #define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET          0x1c0
 #define DRA752_DTEMP_GPU_0_OFFSET                      0x1f4
 #define DRA752_DTEMP_GPU_1_OFFSET                      0x1f8
 #define DRA752_BANDGAP_THRESHOLD_HOT_MASK              (0x3ff << 16)
 #define DRA752_BANDGAP_THRESHOLD_COLD_MASK             (0x3ff << 0)
 
-/* DRA752.TSHUT_THRESHOLD */
-#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK            BIT(31)
-#define DRA752_TSHUT_THRESHOLD_HOT_MASK                        (0x3ff << 16)
-#define DRA752_TSHUT_THRESHOLD_COLD_MASK               (0x3ff << 0)
 
 /* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
 #define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK           (0xffffffff << 0)
 #define DRA752_GPU_MAX_TEMP                            125000
 #define DRA752_GPU_HYST_VAL                            5000
 /* interrupts thresholds */
-#define DRA752_GPU_TSHUT_HOT                           915
-#define DRA752_GPU_TSHUT_COLD                          900
 #define DRA752_GPU_T_HOT                               800
 #define DRA752_GPU_T_COLD                              795
 
 #define DRA752_MPU_MAX_TEMP                            125000
 #define DRA752_MPU_HYST_VAL                            5000
 /* interrupts thresholds */
-#define DRA752_MPU_TSHUT_HOT                           915
-#define DRA752_MPU_TSHUT_COLD                          900
 #define DRA752_MPU_T_HOT                               800
 #define DRA752_MPU_T_COLD                              795
 
 #define DRA752_CORE_MAX_TEMP                           125000
 #define DRA752_CORE_HYST_VAL                           5000
 /* interrupts thresholds */
-#define DRA752_CORE_TSHUT_HOT                          915
-#define DRA752_CORE_TSHUT_COLD                         900
 #define DRA752_CORE_T_HOT                              800
 #define DRA752_CORE_T_COLD                             795
 
 #define DRA752_DSPEVE_MAX_TEMP                         125000
 #define DRA752_DSPEVE_HYST_VAL                         5000
 /* interrupts thresholds */
-#define DRA752_DSPEVE_TSHUT_HOT                                915
-#define DRA752_DSPEVE_TSHUT_COLD                       900
 #define DRA752_DSPEVE_T_HOT                            800
 #define DRA752_DSPEVE_T_COLD                           795
 
 #define DRA752_IVA_MAX_TEMP                            125000
 #define DRA752_IVA_HYST_VAL                            5000
 /* interrupts thresholds */
-#define DRA752_IVA_TSHUT_HOT                           915
-#define DRA752_IVA_TSHUT_COLD                          900
 #define DRA752_IVA_T_HOT                               800
 #define DRA752_IVA_T_COLD                              795
 
index 58b5c6694cd4361472b34fa941890e5121d3dba9..118d7d8477155fd947f3735f0fc7674815de9a23 100644 (file)
@@ -49,9 +49,6 @@ dra752_core_temp_sensor_registers = {
        .bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
        .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
        .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
-       .tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
-       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
-       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
        .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
        .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
        .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
@@ -85,9 +82,6 @@ dra752_iva_temp_sensor_registers = {
        .bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
        .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
        .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
-       .tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
-       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
-       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
        .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
        .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
        .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
@@ -121,9 +115,6 @@ dra752_mpu_temp_sensor_registers = {
        .bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
        .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
        .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
-       .tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
-       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
-       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
        .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
        .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
        .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
@@ -157,9 +148,6 @@ dra752_dspeve_temp_sensor_registers = {
        .bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
        .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
        .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
-       .tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
-       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
-       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
        .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
        .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
        .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
@@ -193,9 +181,6 @@ dra752_gpu_temp_sensor_registers = {
        .bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
        .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
        .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
-       .tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
-       .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
-       .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
        .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
        .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
        .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
@@ -211,8 +196,6 @@ dra752_gpu_temp_sensor_registers = {
 
 /* Thresholds and limits for DRA752 MPU temperature sensor */
 static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
-       .tshut_hot = DRA752_MPU_TSHUT_HOT,
-       .tshut_cold = DRA752_MPU_TSHUT_COLD,
        .t_hot = DRA752_MPU_T_HOT,
        .t_cold = DRA752_MPU_T_COLD,
        .min_freq = DRA752_MPU_MIN_FREQ,
@@ -226,8 +209,6 @@ static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
 
 /* Thresholds and limits for DRA752 GPU temperature sensor */
 static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
-       .tshut_hot = DRA752_GPU_TSHUT_HOT,
-       .tshut_cold = DRA752_GPU_TSHUT_COLD,
        .t_hot = DRA752_GPU_T_HOT,
        .t_cold = DRA752_GPU_T_COLD,
        .min_freq = DRA752_GPU_MIN_FREQ,
@@ -241,8 +222,6 @@ static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
 
 /* Thresholds and limits for DRA752 CORE temperature sensor */
 static struct temp_sensor_data dra752_core_temp_sensor_data = {
-       .tshut_hot = DRA752_CORE_TSHUT_HOT,
-       .tshut_cold = DRA752_CORE_TSHUT_COLD,
        .t_hot = DRA752_CORE_T_HOT,
        .t_cold = DRA752_CORE_T_COLD,
        .min_freq = DRA752_CORE_MIN_FREQ,
@@ -256,8 +235,6 @@ static struct temp_sensor_data dra752_core_temp_sensor_data = {
 
 /* Thresholds and limits for DRA752 DSPEVE temperature sensor */
 static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
-       .tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
-       .tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
        .t_hot = DRA752_DSPEVE_T_HOT,
        .t_cold = DRA752_DSPEVE_T_COLD,
        .min_freq = DRA752_DSPEVE_MIN_FREQ,
@@ -271,8 +248,6 @@ static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
 
 /* Thresholds and limits for DRA752 IVA temperature sensor */
 static struct temp_sensor_data dra752_iva_temp_sensor_data = {
-       .tshut_hot = DRA752_IVA_TSHUT_HOT,
-       .tshut_cold = DRA752_IVA_TSHUT_COLD,
        .t_hot = DRA752_IVA_T_HOT,
        .t_cold = DRA752_IVA_T_COLD,
        .min_freq = DRA752_IVA_MIN_FREQ,
@@ -416,8 +391,7 @@ int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
 
 /* DRA752 data */
 const struct ti_bandgap_data dra752_data = {
-       .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
-                       TI_BANDGAP_FEATURE_FREEZE_BIT |
+       .features = TI_BANDGAP_FEATURE_FREEZE_BIT |
                        TI_BANDGAP_FEATURE_TALERT |
                        TI_BANDGAP_FEATURE_COUNTER_DELAY |
                        TI_BANDGAP_FEATURE_HISTORY_BUFFER |
diff --git a/drivers/thermal/zx2967_thermal.c b/drivers/thermal/zx2967_thermal.c
new file mode 100644 (file)
index 0000000..a5670ad
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * ZTE's zx2967 family thermal sensor driver
+ *
+ * Copyright (C) 2017 ZTE Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+/* Power Mode: 0->low 1->high */
+#define ZX2967_THERMAL_POWER_MODE      0
+#define ZX2967_POWER_MODE_LOW          0
+#define ZX2967_POWER_MODE_HIGH         1
+
+/* DCF Control Register */
+#define ZX2967_THERMAL_DCF             0x4
+#define ZX2967_DCF_EN                  BIT(1)
+#define ZX2967_DCF_FREEZE              BIT(0)
+
+/* Selection Register */
+#define ZX2967_THERMAL_SEL             0x8
+
+/* Control Register */
+#define ZX2967_THERMAL_CTRL            0x10
+
+#define ZX2967_THERMAL_READY           BIT(12)
+#define ZX2967_THERMAL_TEMP_MASK       GENMASK(11, 0)
+#define ZX2967_THERMAL_ID_MASK         0x18
+#define ZX2967_THERMAL_ID              0x10
+
+#define ZX2967_GET_TEMP_TIMEOUT_US     (100 * 1024)
+
+/**
+ * struct zx2967_thermal_priv - zx2967 thermal sensor private structure
+ * @tzd: struct thermal_zone_device where the sensor is registered
+ * @lock: prevents read sensor in parallel
+ * @clk_topcrm: topcrm clk structure
+ * @clk_apb: apb clk structure
+ * @regs: pointer to base address of the thermal sensor
+ */
+
+struct zx2967_thermal_priv {
+       struct thermal_zone_device      *tzd;
+       struct mutex                    lock;
+       struct clk                      *clk_topcrm;
+       struct clk                      *clk_apb;
+       void __iomem                    *regs;
+       struct device                   *dev;
+};
+
+static int zx2967_thermal_get_temp(void *data, int *temp)
+{
+       void __iomem *regs;
+       struct zx2967_thermal_priv *priv = data;
+       u32 val;
+       int ret;
+
+       if (!priv->tzd)
+               return -EAGAIN;
+
+       regs = priv->regs;
+       mutex_lock(&priv->lock);
+       writel_relaxed(ZX2967_POWER_MODE_LOW,
+                      regs + ZX2967_THERMAL_POWER_MODE);
+       writel_relaxed(ZX2967_DCF_EN, regs + ZX2967_THERMAL_DCF);
+
+       val = readl_relaxed(regs + ZX2967_THERMAL_SEL);
+       val &= ~ZX2967_THERMAL_ID_MASK;
+       val |= ZX2967_THERMAL_ID;
+       writel_relaxed(val, regs + ZX2967_THERMAL_SEL);
+
+       /*
+        * Must wait for a while, surely it's a bit odd.
+        * otherwise temperature value we got has a few deviation, even if
+        * the THERMAL_READY bit is set.
+        */
+       usleep_range(100, 300);
+       ret = readx_poll_timeout(readl, regs + ZX2967_THERMAL_CTRL,
+                                val, val & ZX2967_THERMAL_READY, 300,
+                                ZX2967_GET_TEMP_TIMEOUT_US);
+       if (ret) {
+               dev_err(priv->dev, "Thermal sensor data timeout\n");
+               goto unlock;
+       }
+
+       writel_relaxed(ZX2967_DCF_FREEZE | ZX2967_DCF_EN,
+                      regs + ZX2967_THERMAL_DCF);
+       val = readl_relaxed(regs + ZX2967_THERMAL_CTRL)
+                        & ZX2967_THERMAL_TEMP_MASK;
+       writel_relaxed(ZX2967_POWER_MODE_HIGH,
+                      regs + ZX2967_THERMAL_POWER_MODE);
+
+       /*
+        * Calculate temperature
+        * In dts, slope is multiplied by 1000.
+        */
+       *temp = DIV_ROUND_CLOSEST(((s32)val + priv->tzd->tzp->offset) * 1000,
+                                 priv->tzd->tzp->slope);
+
+unlock:
+       mutex_unlock(&priv->lock);
+       return ret;
+}
+
+static struct thermal_zone_of_device_ops zx2967_of_thermal_ops = {
+       .get_temp = zx2967_thermal_get_temp,
+};
+
+static int zx2967_thermal_probe(struct platform_device *pdev)
+{
+       struct zx2967_thermal_priv *priv;
+       struct resource *res;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->regs))
+               return PTR_ERR(priv->regs);
+
+       priv->clk_topcrm = devm_clk_get(&pdev->dev, "topcrm");
+       if (IS_ERR(priv->clk_topcrm)) {
+               ret = PTR_ERR(priv->clk_topcrm);
+               dev_err(&pdev->dev, "failed to get topcrm clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->clk_topcrm);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable topcrm clock: %d\n",
+                       ret);
+               return ret;
+       }
+
+       priv->clk_apb = devm_clk_get(&pdev->dev, "apb");
+       if (IS_ERR(priv->clk_apb)) {
+               ret = PTR_ERR(priv->clk_apb);
+               dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret);
+               goto disable_clk_topcrm;
+       }
+
+       ret = clk_prepare_enable(priv->clk_apb);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable apb clock: %d\n",
+                       ret);
+               goto disable_clk_topcrm;
+       }
+
+       mutex_init(&priv->lock);
+       priv->tzd = thermal_zone_of_sensor_register(&pdev->dev,
+                                       0, priv, &zx2967_of_thermal_ops);
+
+       if (IS_ERR(priv->tzd)) {
+               ret = PTR_ERR(priv->tzd);
+               dev_err(&pdev->dev, "failed to register sensor: %d\n", ret);
+               goto disable_clk_all;
+       }
+
+       if (priv->tzd->tzp->slope == 0) {
+               thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
+               dev_err(&pdev->dev, "coefficients of sensor is invalid\n");
+               ret = -EINVAL;
+               goto disable_clk_all;
+       }
+
+       priv->dev = &pdev->dev;
+       platform_set_drvdata(pdev, priv);
+
+       return 0;
+
+disable_clk_all:
+       clk_disable_unprepare(priv->clk_apb);
+disable_clk_topcrm:
+       clk_disable_unprepare(priv->clk_topcrm);
+       return ret;
+}
+
+static int zx2967_thermal_exit(struct platform_device *pdev)
+{
+       struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
+
+       thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
+       clk_disable_unprepare(priv->clk_topcrm);
+       clk_disable_unprepare(priv->clk_apb);
+
+       return 0;
+}
+
+static const struct of_device_id zx2967_thermal_id_table[] = {
+       { .compatible = "zte,zx296718-thermal" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table);
+
+#ifdef CONFIG_PM_SLEEP
+static int zx2967_thermal_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
+
+       if (priv && priv->clk_topcrm)
+               clk_disable_unprepare(priv->clk_topcrm);
+
+       if (priv && priv->clk_apb)
+               clk_disable_unprepare(priv->clk_apb);
+
+       return 0;
+}
+
+static int zx2967_thermal_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
+       int error;
+
+       error = clk_prepare_enable(priv->clk_topcrm);
+       if (error)
+               return error;
+
+       error = clk_prepare_enable(priv->clk_apb);
+       if (error) {
+               clk_disable_unprepare(priv->clk_topcrm);
+               return error;
+       }
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops,
+                        zx2967_thermal_suspend, zx2967_thermal_resume);
+
+static struct platform_driver zx2967_thermal_driver = {
+       .probe = zx2967_thermal_probe,
+       .remove = zx2967_thermal_exit,
+       .driver = {
+               .name = "zx2967_thermal",
+               .of_match_table = zx2967_thermal_id_table,
+               .pm = &zx2967_thermal_pm_ops,
+       },
+};
+module_platform_driver(zx2967_thermal_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE zx2967 thermal driver");
+MODULE_LICENSE("GPL v2");
index e275e98bdceb46fe1e8550a0d0c3ff4d18de80f3..dab11f97e1c6377cd9bf4af142a5bcd5b64c024e 100644 (file)
@@ -194,7 +194,7 @@ struct thermal_attr {
  * @governor:  pointer to the governor for this thermal zone
  * @governor_data:     private pointer for governor data
  * @thermal_instances: list of &struct thermal_instance of this thermal zone
- * @idr:       &struct idr to generate unique id for this zone's cooling
+ * @ida:       &struct ida to generate unique id for this zone's cooling
  *             devices
  * @lock:      lock to protect thermal_instances list
  * @node:      node in thermal_tz_list (in thermal_core.c)
@@ -227,7 +227,7 @@ struct thermal_zone_device {
        struct thermal_governor *governor;
        void *governor_data;
        struct list_head thermal_instances;
-       struct idr idr;
+       struct ida ida;
        struct mutex lock;
        struct list_head node;
        struct delayed_work poll_queue;