ipq806x: add thermal sensor driver
authordissent1 <be.dissent+github@gmail.com>
Sat, 5 Nov 2016 13:15:33 +0000 (16:15 +0300)
committerJohn Crispin <john@phrozen.org>
Thu, 1 Dec 2016 14:47:43 +0000 (15:47 +0100)
Allows to check cpu temperature.

Huge thanks to @hnyman for valuable assistance!

Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
16 files changed:
target/linux/ipq806x/config-4.4
target/linux/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi
target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/015-2-thermal-qcom-tsens-8916-Add-support-for-8916-family-of-SoCs.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/015-3-thermal-qcom-tsens-8974-Add-support-for-8974-family-of-SoCs.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/015-4-thermal-qcom-tsens-8960-Add-support-for-8960-family-of-SoCs.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/015-8-qcom-tsens-8916-mark-PM-functions-__maybe_unused.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/016-2-thermal-of-thermal-Add-devm-version-of.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/017-09-thermal-core-export-apis-to-get-slope-and-offset.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/019-1-nvmem-core-return-error-for-non-word-aligned-access.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/019-2-nvmem-core-fix-error-path-in-nvmem_add_cells.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/019-3-nvmem-Add-flag-to-export-NVMEM-to-root-only.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/019-4-nvmem-Add-backwards-compatibility-support-for-older-EEPROM-drivers.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/309-clk-gcc-add-tsens-child-node.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/310-add-necessary-thermal-data.patch [new file with mode: 0644]
target/linux/ipq806x/patches-4.4/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch

index 56a225448900bd46e4a07f555478e1e909479758..cdb20ebb058d65fb069535f5d36e432c8a15d086 100644 (file)
@@ -352,6 +352,7 @@ CONFIG_QCOM_SCM=y
 CONFIG_QCOM_SCM_32=y
 # CONFIG_QCOM_SMD is not set
 CONFIG_QCOM_SMEM=y
+CONFIG_QCOM_TSENS=y
 CONFIG_QCOM_WDT=y
 CONFIG_RAS=y
 CONFIG_RATIONAL=y
index e0ba99a41cff70e2c4f1d8d175e6bd9c28e0d9d7..614610c0168d5d39c86302a5053dc6303f60ed63 100644 (file)
                };
        };
 
+       thermal-zones {
+               cpu-thermal0 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&gcc 5>;
+                       coefficients = <1132 0>;
+
+                       trips {
+                               cpu_alert0: trip0 {
+                                       temperature = <75000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu_crit0: trip1 {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu-thermal1 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&gcc 6>;
+                       coefficients = <1132 0>;
+
+                       trips {
+                               cpu_alert1: trip0 {
+                                       temperature = <75000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu_crit1: trip1 {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu-thermal2 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&gcc 7>;
+                       coefficients = <1199 0>;
+
+                       trips {
+                               cpu_alert2: trip0 {
+                                       temperature = <75000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu_crit2: trip1 {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+
+               cpu-thermal3 {
+                       polling-delay-passive = <250>;
+                       polling-delay = <1000>;
+
+                       thermal-sensors = <&gcc 8>;
+                       coefficients = <1132 0>;
+
+                       trips {
+                               cpu_alert3: trip0 {
+                                       temperature = <75000>;
+                                       hysteresis = <2000>;
+                                       type = "passive";
+                               };
+                               cpu_crit3: trip1 {
+                                       temperature = <110000>;
+                                       hysteresis = <2000>;
+                                       type = "critical";
+                               };
+                       };
+               };
+       };
+
        cpu-pmu {
                compatible = "qcom,krait-pmu";
                interrupts = <1 10 0x304>;
                        reg = <0x00700000 0x1000>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       stride = <1>;
-                       ranges = <0x0 0x00700000 0x1000>;
+                       ranges;
+
+                       tsens_calib: calib {
+                               reg = <0x400 0x10>;
+                       };
+                       tsens_backup: backup_calib {
+                               reg = <0x410 0x10>;
+                       };
                };
 
                rpm@108000 {
                gcc: clock-controller@900000 {
                        compatible = "qcom,gcc-ipq8064";
                        reg = <0x00900000 0x4000>;
+                       nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+                       nvmem-cell-names = "calib", "calib_backup";
                        #clock-cells = <1>;
                        #reset-cells = <1>;
                        #power-domain-cells = <1>;
+                       #thermal-sensor-cells = <1>;
                };
 
                lcc: clock-controller@28000000 {
                        reg = <0x1a400000 0x100>;
                };
 
-               tsens: tsens-ipq806x {
-                       compatible = "qcom,ipq806x-tsens";
-                       reg = <0x900000 0x3678>, <0x700000 0x420>;
-                       reg-names = "tsens_physical", "tsens_eeprom_physical";
-                       interrupts = <0 178 0>;
-                       qcom,sensors = <11>;
-                       qcom,tsens_factor = <1000>;
-                       qcom,slope = <1176 1176 1154 1176 1111 1132 1132 1199 1132 1199 1132>;
-               };
-
                qcom,msm-thermal {
                        compatible = "qcom,msm-thermal";
                        qcom,sensor-id = <0>;
diff --git a/target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch b/target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch
new file mode 100644 (file)
index 0000000..ef7e2f4
--- /dev/null
@@ -0,0 +1,536 @@
+From 9066073c6c27994a30187abf3b674770b4088348 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Thu, 5 May 2016 14:21:39 +0530
+Subject: thermal: qcom: tsens: Add a skeletal TSENS drivers
+
+TSENS is Qualcomms' thermal temperature sensor device. It
+supports reading temperatures from multiple thermal sensors
+present on various QCOM SoCs.
+Calibration data is generally read from a non-volatile memory
+(eeprom) device.
+
+Add a skeleton driver with all the necessary abstractions so
+a variety of qcom device families which support TSENS can
+add driver extensions.
+
+Also add the required device tree bindings which can be used
+to describe the TSENS device in DT.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Reviewed-by: Lina Iyer <lina.iyer@linaro.org>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ .../devicetree/bindings/thermal/qcom-tsens.txt     |  21 +++
+ drivers/thermal/Kconfig                            |   5 +
+ drivers/thermal/Makefile                           |   1 +
+ drivers/thermal/qcom/Kconfig                       |  11 ++
+ drivers/thermal/qcom/Makefile                      |   2 +
+ drivers/thermal/qcom/tsens-common.c                | 141 +++++++++++++++
+ drivers/thermal/qcom/tsens.c                       | 195 +++++++++++++++++++++
+ drivers/thermal/qcom/tsens.h                       |  90 ++++++++++
+ 8 files changed, 466 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+ create mode 100644 drivers/thermal/qcom/Kconfig
+ create mode 100644 drivers/thermal/qcom/Makefile
+ create mode 100644 drivers/thermal/qcom/tsens-common.c
+ create mode 100644 drivers/thermal/qcom/tsens.c
+ create mode 100644 drivers/thermal/qcom/tsens.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+@@ -0,0 +1,21 @@
++* QCOM SoC Temperature Sensor (TSENS)
++
++Required properties:
++- compatible :
++ - "qcom,msm8916-tsens" : For 8916 Family of SoCs
++ - "qcom,msm8974-tsens" : For 8974 Family of SoCs
++ - "qcom,msm8996-tsens" : For 8996 Family of SoCs
++
++- reg: Address range of the thermal registers
++- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
++- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
++nvmem cells
++
++Example:
++tsens: thermal-sensor@900000 {
++              compatible = "qcom,msm8916-tsens";
++              reg = <0x4a8000 0x2000>;
++              nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
++              nvmem-cell-names = "caldata", "calsel";
++              #thermal-sensor-cells = <1>;
++      };
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -391,4 +391,9 @@ config QCOM_SPMI_TEMP_ALARM
+         real time die temperature if an ADC is present or an estimate of the
+         temperature based upon the over temperature stage value.
++menu "Qualcomm thermal drivers"
++depends on (ARCH_QCOM && OF) || COMPILE_TEST
++source "drivers/thermal/qcom/Kconfig"
++endmenu
++
+ endif
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -48,3 +48,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL)      += intel
+ obj-$(CONFIG_ST_THERMAL)      += st/
+ obj-$(CONFIG_TEGRA_SOCTHERM)  += tegra_soctherm.o
+ obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
++obj-$(CONFIG_QCOM_TSENS)      += qcom/
+--- /dev/null
++++ b/drivers/thermal/qcom/Kconfig
+@@ -0,0 +1,11 @@
++config QCOM_TSENS
++      tristate "Qualcomm TSENS Temperature Alarm"
++      depends on THERMAL
++      depends on QCOM_QFPROM
++      depends on ARCH_QCOM || COMPILE_TEST
++      help
++        This enables the thermal sysfs driver for the TSENS device. It shows
++        up in Sysfs as a thermal zone with multiple trip points. Disabling the
++        thermal zone device via the mode file results in disabling the sensor.
++        Also able to set threshold temperature for both hot and cold and update
++        when a threshold is reached.
+--- /dev/null
++++ b/drivers/thermal/qcom/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_QCOM_TSENS)      += qcom_tsens.o
++qcom_tsens-y                  += tsens.o tsens-common.o
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens-common.c
+@@ -0,0 +1,141 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * 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/err.h>
++#include <linux/io.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include "tsens.h"
++
++#define S0_ST_ADDR            0x1030
++#define SN_ADDR_OFFSET                0x4
++#define SN_ST_TEMP_MASK               0x3ff
++#define CAL_DEGC_PT1          30
++#define CAL_DEGC_PT2          120
++#define SLOPE_FACTOR          1000
++#define SLOPE_DEFAULT         3200
++
++char *qfprom_read(struct device *dev, const char *cname)
++{
++      struct nvmem_cell *cell;
++      ssize_t data;
++      char *ret;
++
++      cell = nvmem_cell_get(dev, cname);
++      if (IS_ERR(cell))
++              return ERR_CAST(cell);
++
++      ret = nvmem_cell_read(cell, &data);
++      nvmem_cell_put(cell);
++
++      return ret;
++}
++
++/*
++ * Use this function on devices where slope and offset calculations
++ * depend on calibration data read from qfprom. On others the slope
++ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
++ * resp.
++ */
++void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
++                           u32 *p2, u32 mode)
++{
++      int i;
++      int num, den;
++
++      for (i = 0; i < tmdev->num_sensors; i++) {
++              dev_dbg(tmdev->dev,
++                      "sensor%d - data_point1:%#x data_point2:%#x\n",
++                      i, p1[i], p2[i]);
++
++              tmdev->sensor[i].slope = SLOPE_DEFAULT;
++              if (mode == TWO_PT_CALIB) {
++                      /*
++                       * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
++                       *      temp_120_degc - temp_30_degc (x2 - x1)
++                       */
++                      num = p2[i] - p1[i];
++                      num *= SLOPE_FACTOR;
++                      den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
++                      tmdev->sensor[i].slope = num / den;
++              }
++
++              tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
++                              (CAL_DEGC_PT1 *
++                              tmdev->sensor[i].slope);
++              dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset);
++      }
++}
++
++static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
++{
++      int degc, num, den;
++
++      num = (adc_code * SLOPE_FACTOR) - s->offset;
++      den = s->slope;
++
++      if (num > 0)
++              degc = num + (den / 2);
++      else if (num < 0)
++              degc = num - (den / 2);
++      else
++              degc = num;
++
++      degc /= den;
++
++      return degc;
++}
++
++int get_temp_common(struct tsens_device *tmdev, int id, int *temp)
++{
++      struct tsens_sensor *s = &tmdev->sensor[id];
++      u32 code;
++      unsigned int sensor_addr;
++      int last_temp = 0, ret;
++
++      sensor_addr = S0_ST_ADDR + s->hw_id * SN_ADDR_OFFSET;
++      ret = regmap_read(tmdev->map, sensor_addr, &code);
++      if (ret)
++              return ret;
++      last_temp = code & SN_ST_TEMP_MASK;
++
++      *temp = code_to_degc(last_temp, s) * 1000;
++
++      return 0;
++}
++
++static const struct regmap_config tsens_config = {
++      .reg_bits       = 32,
++      .val_bits       = 32,
++      .reg_stride     = 4,
++};
++
++int __init init_common(struct tsens_device *tmdev)
++{
++      void __iomem *base;
++
++      base = of_iomap(tmdev->dev->of_node, 0);
++      if (IS_ERR(base))
++              return -EINVAL;
++
++      tmdev->map = devm_regmap_init_mmio(tmdev->dev, base, &tsens_config);
++      if (!tmdev->map) {
++              iounmap(base);
++              return -ENODEV;
++      }
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens.c
+@@ -0,0 +1,195 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * 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/err.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/thermal.h>
++#include "tsens.h"
++
++static int tsens_get_temp(void *data, int *temp)
++{
++      const struct tsens_sensor *s = data;
++      struct tsens_device *tmdev = s->tmdev;
++
++      return tmdev->ops->get_temp(tmdev, s->id, temp);
++}
++
++static int tsens_get_trend(void *data, long *temp)
++{
++      const struct tsens_sensor *s = data;
++      struct tsens_device *tmdev = s->tmdev;
++
++      if (tmdev->ops->get_trend)
++              return tmdev->ops->get_trend(tmdev, s->id, temp);
++
++      return -ENOTSUPP;
++}
++
++static int tsens_suspend(struct device *dev)
++{
++      struct tsens_device *tmdev = dev_get_drvdata(dev);
++
++      if (tmdev->ops && tmdev->ops->suspend)
++              return tmdev->ops->suspend(tmdev);
++
++      return 0;
++}
++
++static int tsens_resume(struct device *dev)
++{
++      struct tsens_device *tmdev = dev_get_drvdata(dev);
++
++      if (tmdev->ops && tmdev->ops->resume)
++              return tmdev->ops->resume(tmdev);
++
++      return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
++
++static const struct of_device_id tsens_table[] = {
++      {
++              .compatible = "qcom,msm8916-tsens",
++      }, {
++              .compatible = "qcom,msm8974-tsens",
++      },
++      {}
++};
++MODULE_DEVICE_TABLE(of, tsens_table);
++
++static const struct thermal_zone_of_device_ops tsens_of_ops = {
++      .get_temp = tsens_get_temp,
++      .get_trend = tsens_get_trend,
++};
++
++static int tsens_register(struct tsens_device *tmdev)
++{
++      int i;
++      struct thermal_zone_device *tzd;
++      u32 *hw_id, n = tmdev->num_sensors;
++
++      hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
++      if (!hw_id)
++              return -ENOMEM;
++
++      for (i = 0;  i < tmdev->num_sensors; i++) {
++              tmdev->sensor[i].tmdev = tmdev;
++              tmdev->sensor[i].id = i;
++              tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i,
++                                                         &tmdev->sensor[i],
++                                                         &tsens_of_ops);
++              if (IS_ERR(tzd))
++                      continue;
++              tmdev->sensor[i].tzd = tzd;
++              if (tmdev->ops->enable)
++                      tmdev->ops->enable(tmdev, i);
++      }
++      return 0;
++}
++
++static int tsens_probe(struct platform_device *pdev)
++{
++      int ret, i;
++      struct device *dev;
++      struct device_node *np;
++      struct tsens_sensor *s;
++      struct tsens_device *tmdev;
++      const struct tsens_data *data;
++      const struct of_device_id *id;
++
++      if (pdev->dev.of_node)
++              dev = &pdev->dev;
++      else
++              dev = pdev->dev.parent;
++
++      np = dev->of_node;
++
++      id = of_match_node(tsens_table, np);
++      if (!id)
++              return -EINVAL;
++
++      data = id->data;
++
++      if (data->num_sensors <= 0) {
++              dev_err(dev, "invalid number of sensors\n");
++              return -EINVAL;
++      }
++
++      tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
++                           data->num_sensors * sizeof(*s), GFP_KERNEL);
++      if (!tmdev)
++              return -ENOMEM;
++
++      tmdev->dev = dev;
++      tmdev->num_sensors = data->num_sensors;
++      tmdev->ops = data->ops;
++      for (i = 0;  i < tmdev->num_sensors; i++) {
++              if (data->hw_ids)
++                      tmdev->sensor[i].hw_id = data->hw_ids[i];
++              else
++                      tmdev->sensor[i].hw_id = i;
++      }
++
++      if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp)
++              return -EINVAL;
++
++      ret = tmdev->ops->init(tmdev);
++      if (ret < 0) {
++              dev_err(dev, "tsens init failed\n");
++              return ret;
++      }
++
++      if (tmdev->ops->calibrate) {
++              ret = tmdev->ops->calibrate(tmdev);
++              if (ret < 0) {
++                      dev_err(dev, "tsens calibration failed\n");
++                      return ret;
++              }
++      }
++
++      ret = tsens_register(tmdev);
++
++      platform_set_drvdata(pdev, tmdev);
++
++      return ret;
++}
++
++static int tsens_remove(struct platform_device *pdev)
++{
++      struct tsens_device *tmdev = platform_get_drvdata(pdev);
++
++      if (tmdev->ops->disable)
++              tmdev->ops->disable(tmdev);
++
++      return 0;
++}
++
++static struct platform_driver tsens_driver = {
++      .probe = tsens_probe,
++      .remove = tsens_remove,
++      .driver = {
++              .name = "qcom-tsens",
++              .pm     = &tsens_pm_ops,
++              .of_match_table = tsens_table,
++      },
++};
++module_platform_driver(tsens_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("QCOM Temperature Sensor driver");
++MODULE_ALIAS("platform:qcom-tsens");
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens.h
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * 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.
++ */
++#ifndef __QCOM_TSENS_H__
++#define __QCOM_TSENS_H__
++
++#define ONE_PT_CALIB          0x1
++#define ONE_PT_CALIB2         0x2
++#define TWO_PT_CALIB          0x3
++
++struct tsens_device;
++
++struct tsens_sensor {
++      struct tsens_device             *tmdev;
++      struct thermal_zone_device      *tzd;
++      int                             offset;
++      int                             id;
++      int                             hw_id;
++      int                             slope;
++      u32                             status;
++};
++
++/**
++ * struct tsens_ops - operations as supported by the tsens device
++ * @init: Function to initialize the tsens device
++ * @calibrate: Function to calibrate the tsens device
++ * @get_temp: Function which returns the temp in millidegC
++ * @enable: Function to enable (clocks/power) tsens device
++ * @disable: Function to disable the tsens device
++ * @suspend: Function to suspend the tsens device
++ * @resume: Function to resume the tsens device
++ * @get_trend: Function to get the thermal/temp trend
++ */
++struct tsens_ops {
++      /* mandatory callbacks */
++      int (*init)(struct tsens_device *);
++      int (*calibrate)(struct tsens_device *);
++      int (*get_temp)(struct tsens_device *, int, int *);
++      /* optional callbacks */
++      int (*enable)(struct tsens_device *, int);
++      void (*disable)(struct tsens_device *);
++      int (*suspend)(struct tsens_device *);
++      int (*resume)(struct tsens_device *);
++      int (*get_trend)(struct tsens_device *, int, long *);
++};
++
++/**
++ * struct tsens_data - tsens instance specific data
++ * @num_sensors: Max number of sensors supported by platform
++ * @ops: operations the tsens instance supports
++ * @hw_ids: Subset of sensors ids supported by platform, if not the first n
++ */
++struct tsens_data {
++      const u32               num_sensors;
++      const struct tsens_ops  *ops;
++      unsigned int            *hw_ids;
++};
++
++/* Registers to be saved/restored across a context loss */
++struct tsens_context {
++      int     threshold;
++      int     control;
++};
++
++struct tsens_device {
++      struct device                   *dev;
++      u32                             num_sensors;
++      struct regmap                   *map;
++      struct regmap_field             *status_field;
++      struct tsens_context            ctx;
++      bool                            trdy;
++      const struct tsens_ops          *ops;
++      struct tsens_sensor             sensor[0];
++};
++
++char *qfprom_read(struct device *, const char *);
++void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
++int init_common(struct tsens_device *);
++int get_temp_common(struct tsens_device *, int, int *);
++
++#endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq806x/patches-4.4/015-2-thermal-qcom-tsens-8916-Add-support-for-8916-family-of-SoCs.patch b/target/linux/ipq806x/patches-4.4/015-2-thermal-qcom-tsens-8916-Add-support-for-8916-family-of-SoCs.patch
new file mode 100644 (file)
index 0000000..d076196
--- /dev/null
@@ -0,0 +1,165 @@
+From 840a5bd3ed3fdd62456d4d26c3128ec10496555b Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Thu, 5 May 2016 14:21:40 +0530
+Subject: thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
+
+Add support to calibrate sensors on 8916 family and also add common
+functions to read temperature from sensors (This can be reused on
+other SoCs having similar TSENS device)
+The calibration data is read from eeprom using the generic nvmem
+framework apis.
+
+Based on the original code by Siddartha Mohanadoss and Stephen Boyd.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ drivers/thermal/qcom/Makefile     |   2 +-
+ drivers/thermal/qcom/tsens-8916.c | 113 ++++++++++++++++++++++++++++++++++++++
+ drivers/thermal/qcom/tsens.c      |   1 +
+ drivers/thermal/qcom/tsens.h      |   2 +
+ 4 files changed, 117 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/thermal/qcom/tsens-8916.c
+
+--- a/drivers/thermal/qcom/Makefile
++++ b/drivers/thermal/qcom/Makefile
+@@ -1,2 +1,2 @@
+ obj-$(CONFIG_QCOM_TSENS)      += qcom_tsens.o
+-qcom_tsens-y                  += tsens.o tsens-common.o
++qcom_tsens-y                  += tsens.o tsens-common.o tsens-8916.o
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens-8916.c
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * 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/platform_device.h>
++#include "tsens.h"
++
++/* eeprom layout data for 8916 */
++#define BASE0_MASK    0x0000007f
++#define BASE1_MASK    0xfe000000
++#define BASE0_SHIFT   0
++#define BASE1_SHIFT   25
++
++#define S0_P1_MASK    0x00000f80
++#define S1_P1_MASK    0x003e0000
++#define S2_P1_MASK    0xf8000000
++#define S3_P1_MASK    0x000003e0
++#define S4_P1_MASK    0x000f8000
++
++#define S0_P2_MASK    0x0001f000
++#define S1_P2_MASK    0x07c00000
++#define S2_P2_MASK    0x0000001f
++#define S3_P2_MASK    0x00007c00
++#define S4_P2_MASK    0x01f00000
++
++#define S0_P1_SHIFT   7
++#define S1_P1_SHIFT   17
++#define S2_P1_SHIFT   27
++#define S3_P1_SHIFT   5
++#define S4_P1_SHIFT   15
++
++#define S0_P2_SHIFT   12
++#define S1_P2_SHIFT   22
++#define S2_P2_SHIFT   0
++#define S3_P2_SHIFT   10
++#define S4_P2_SHIFT   20
++
++#define CAL_SEL_MASK  0xe0000000
++#define CAL_SEL_SHIFT 29
++
++static int calibrate_8916(struct tsens_device *tmdev)
++{
++      int base0 = 0, base1 = 0, i;
++      u32 p1[5], p2[5];
++      int mode = 0;
++      u32 *qfprom_cdata, *qfprom_csel;
++
++      qfprom_cdata = (u32 *)qfprom_read(tmdev->dev, "calib");
++      if (IS_ERR(qfprom_cdata))
++              return PTR_ERR(qfprom_cdata);
++
++      qfprom_csel = (u32 *)qfprom_read(tmdev->dev, "calib_sel");
++      if (IS_ERR(qfprom_csel))
++              return PTR_ERR(qfprom_csel);
++
++      mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT;
++      dev_dbg(tmdev->dev, "calibration mode is %d\n", mode);
++
++      switch (mode) {
++      case TWO_PT_CALIB:
++              base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
++              p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT;
++              p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT;
++              p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT;
++              p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT;
++              p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT;
++              for (i = 0; i < tmdev->num_sensors; i++)
++                      p2[i] = ((base1 + p2[i]) << 3);
++              /* Fall through */
++      case ONE_PT_CALIB2:
++              base0 = (qfprom_cdata[0] & BASE0_MASK);
++              p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
++              p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT;
++              p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT;
++              p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT;
++              p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT;
++              for (i = 0; i < tmdev->num_sensors; i++)
++                      p1[i] = (((base0) + p1[i]) << 3);
++              break;
++      default:
++              for (i = 0; i < tmdev->num_sensors; i++) {
++                      p1[i] = 500;
++                      p2[i] = 780;
++              }
++              break;
++      }
++
++      compute_intercept_slope(tmdev, p1, p2, mode);
++
++      return 0;
++}
++
++const struct tsens_ops ops_8916 = {
++      .init           = init_common,
++      .calibrate      = calibrate_8916,
++      .get_temp       = get_temp_common,
++};
++
++const struct tsens_data data_8916 = {
++      .num_sensors    = 5,
++      .ops            = &ops_8916,
++      .hw_ids         = (unsigned int []){0, 1, 2, 4, 5 },
++};
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t
+ static const struct of_device_id tsens_table[] = {
+       {
+               .compatible = "qcom,msm8916-tsens",
++              .data = &data_8916,
+       }, {
+               .compatible = "qcom,msm8974-tsens",
+       },
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -87,4 +87,6 @@ void compute_intercept_slope(struct tsen
+ int init_common(struct tsens_device *);
+ int get_temp_common(struct tsens_device *, int, int *);
++extern const struct tsens_data data_8916;
++
+ #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq806x/patches-4.4/015-3-thermal-qcom-tsens-8974-Add-support-for-8974-family-of-SoCs.patch b/target/linux/ipq806x/patches-4.4/015-3-thermal-qcom-tsens-8974-Add-support-for-8974-family-of-SoCs.patch
new file mode 100644 (file)
index 0000000..671f461
--- /dev/null
@@ -0,0 +1,293 @@
+From 5e6703bd2d83548998848865cb9a9a795f31a311 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Thu, 5 May 2016 14:21:41 +0530
+Subject: thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
+
+Add .calibrate support for 8974 family as part of tsens_ops.
+
+Based on the original code by Siddartha Mohanadoss and Stephen Boyd.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ drivers/thermal/qcom/Makefile     |   2 +-
+ drivers/thermal/qcom/tsens-8974.c | 244 ++++++++++++++++++++++++++++++++++++++
+ drivers/thermal/qcom/tsens.c      |   1 +
+ drivers/thermal/qcom/tsens.h      |   2 +-
+ 4 files changed, 247 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/thermal/qcom/tsens-8974.c
+
+--- a/drivers/thermal/qcom/Makefile
++++ b/drivers/thermal/qcom/Makefile
+@@ -1,2 +1,2 @@
+ obj-$(CONFIG_QCOM_TSENS)      += qcom_tsens.o
+-qcom_tsens-y                  += tsens.o tsens-common.o tsens-8916.o
++qcom_tsens-y                  += tsens.o tsens-common.o tsens-8916.o tsens-8974.o
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens-8974.c
+@@ -0,0 +1,244 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * 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/platform_device.h>
++#include "tsens.h"
++
++/* eeprom layout data for 8974 */
++#define BASE1_MASK            0xff
++#define S0_P1_MASK            0x3f00
++#define S1_P1_MASK            0xfc000
++#define S2_P1_MASK            0x3f00000
++#define S3_P1_MASK            0xfc000000
++#define S4_P1_MASK            0x3f
++#define S5_P1_MASK            0xfc0
++#define S6_P1_MASK            0x3f000
++#define S7_P1_MASK            0xfc0000
++#define S8_P1_MASK            0x3f000000
++#define S8_P1_MASK_BKP                0x3f
++#define S9_P1_MASK            0x3f
++#define S9_P1_MASK_BKP                0xfc0
++#define S10_P1_MASK           0xfc0
++#define S10_P1_MASK_BKP               0x3f000
++#define CAL_SEL_0_1           0xc0000000
++#define CAL_SEL_2             0x40000000
++#define CAL_SEL_SHIFT         30
++#define CAL_SEL_SHIFT_2               28
++
++#define S0_P1_SHIFT           8
++#define S1_P1_SHIFT           14
++#define S2_P1_SHIFT           20
++#define S3_P1_SHIFT           26
++#define S5_P1_SHIFT           6
++#define S6_P1_SHIFT           12
++#define S7_P1_SHIFT           18
++#define S8_P1_SHIFT           24
++#define S9_P1_BKP_SHIFT               6
++#define S10_P1_SHIFT          6
++#define S10_P1_BKP_SHIFT      12
++
++#define BASE2_SHIFT           12
++#define BASE2_BKP_SHIFT               18
++#define S0_P2_SHIFT           20
++#define S0_P2_BKP_SHIFT               26
++#define S1_P2_SHIFT           26
++#define S2_P2_BKP_SHIFT               6
++#define S3_P2_SHIFT           6
++#define S3_P2_BKP_SHIFT               12
++#define S4_P2_SHIFT           12
++#define S4_P2_BKP_SHIFT               18
++#define S5_P2_SHIFT           18
++#define S5_P2_BKP_SHIFT               24
++#define S6_P2_SHIFT           24
++#define S7_P2_BKP_SHIFT               6
++#define S8_P2_SHIFT           6
++#define S8_P2_BKP_SHIFT               12
++#define S9_P2_SHIFT           12
++#define S9_P2_BKP_SHIFT               18
++#define S10_P2_SHIFT          18
++#define S10_P2_BKP_SHIFT      24
++
++#define BASE2_MASK            0xff000
++#define BASE2_BKP_MASK                0xfc0000
++#define S0_P2_MASK            0x3f00000
++#define S0_P2_BKP_MASK                0xfc000000
++#define S1_P2_MASK            0xfc000000
++#define S1_P2_BKP_MASK                0x3f
++#define S2_P2_MASK            0x3f
++#define S2_P2_BKP_MASK                0xfc0
++#define S3_P2_MASK            0xfc0
++#define S3_P2_BKP_MASK                0x3f000
++#define S4_P2_MASK            0x3f000
++#define S4_P2_BKP_MASK                0xfc0000
++#define S5_P2_MASK            0xfc0000
++#define S5_P2_BKP_MASK                0x3f000000
++#define S6_P2_MASK            0x3f000000
++#define S6_P2_BKP_MASK                0x3f
++#define S7_P2_MASK            0x3f
++#define S7_P2_BKP_MASK                0xfc0
++#define S8_P2_MASK            0xfc0
++#define S8_P2_BKP_MASK                0x3f000
++#define S9_P2_MASK            0x3f000
++#define S9_P2_BKP_MASK                0xfc0000
++#define S10_P2_MASK           0xfc0000
++#define S10_P2_BKP_MASK               0x3f000000
++
++#define BKP_SEL                       0x3
++#define BKP_REDUN_SEL         0xe0000000
++#define BKP_REDUN_SHIFT               29
++
++#define BIT_APPEND            0x3
++
++static int calibrate_8974(struct tsens_device *tmdev)
++{
++      int base1 = 0, base2 = 0, i;
++      u32 p1[11], p2[11];
++      int mode = 0;
++      u32 *calib, *bkp;
++      u32 calib_redun_sel;
++
++      calib = (u32 *)qfprom_read(tmdev->dev, "calib");
++      if (IS_ERR(calib))
++              return PTR_ERR(calib);
++
++      bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup");
++      if (IS_ERR(bkp))
++              return PTR_ERR(bkp);
++
++      calib_redun_sel =  bkp[1] & BKP_REDUN_SEL;
++      calib_redun_sel >>= BKP_REDUN_SHIFT;
++
++      if (calib_redun_sel == BKP_SEL) {
++              mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
++              mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
++
++              switch (mode) {
++              case TWO_PT_CALIB:
++                      base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT;
++                      p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT;
++                      p2[1] = (bkp[3] & S1_P2_BKP_MASK);
++                      p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT;
++                      p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT;
++                      p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT;
++                      p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT;
++                      p2[6] = (calib[5] & S6_P2_BKP_MASK);
++                      p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT;
++                      p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT;
++                      p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT;
++                      p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT;
++                      /* Fall through */
++              case ONE_PT_CALIB:
++              case ONE_PT_CALIB2:
++                      base1 = bkp[0] & BASE1_MASK;
++                      p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT;
++                      p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT;
++                      p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT;
++                      p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT;
++                      p1[4] = (bkp[1] & S4_P1_MASK);
++                      p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT;
++                      p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT;
++                      p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT;
++                      p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT;
++                      p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT;
++                      p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT;
++                      break;
++              }
++      } else {
++              mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT;
++              mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2;
++
++              switch (mode) {
++              case TWO_PT_CALIB:
++                      base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT;
++                      p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT;
++                      p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT;
++                      p2[2] = (calib[3] & S2_P2_MASK);
++                      p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT;
++                      p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT;
++                      p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT;
++                      p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT;
++                      p2[7] = (calib[4] & S7_P2_MASK);
++                      p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT;
++                      p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT;
++                      p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT;
++                      /* Fall through */
++              case ONE_PT_CALIB:
++              case ONE_PT_CALIB2:
++                      base1 = calib[0] & BASE1_MASK;
++                      p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT;
++                      p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT;
++                      p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT;
++                      p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT;
++                      p1[4] = (calib[1] & S4_P1_MASK);
++                      p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT;
++                      p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT;
++                      p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT;
++                      p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT;
++                      p1[9] = (calib[2] & S9_P1_MASK);
++                      p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT;
++                      break;
++              }
++      }
++
++      switch (mode) {
++      case ONE_PT_CALIB:
++              for (i = 0; i < tmdev->num_sensors; i++)
++                      p1[i] += (base1 << 2) | BIT_APPEND;
++              break;
++      case TWO_PT_CALIB:
++              for (i = 0; i < tmdev->num_sensors; i++) {
++                      p2[i] += base2;
++                      p2[i] <<= 2;
++                      p2[i] |= BIT_APPEND;
++              }
++              /* Fall through */
++      case ONE_PT_CALIB2:
++              for (i = 0; i < tmdev->num_sensors; i++) {
++                      p1[i] += base1;
++                      p1[i] <<= 2;
++                      p1[i] |= BIT_APPEND;
++              }
++              break;
++      default:
++              for (i = 0; i < tmdev->num_sensors; i++)
++                      p2[i] = 780;
++              p1[0] = 502;
++              p1[1] = 509;
++              p1[2] = 503;
++              p1[3] = 509;
++              p1[4] = 505;
++              p1[5] = 509;
++              p1[6] = 507;
++              p1[7] = 510;
++              p1[8] = 508;
++              p1[9] = 509;
++              p1[10] = 508;
++              break;
++      }
++
++      compute_intercept_slope(tmdev, p1, p2, mode);
++
++      return 0;
++}
++
++const struct tsens_ops ops_8974 = {
++      .init           = init_common,
++      .calibrate      = calibrate_8974,
++      .get_temp       = get_temp_common,
++};
++
++const struct tsens_data data_8974 = {
++      .num_sensors    = 11,
++      .ops            = &ops_8974,
++};
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -68,6 +68,7 @@ static const struct of_device_id tsens_t
+               .data = &data_8916,
+       }, {
+               .compatible = "qcom,msm8974-tsens",
++              .data = &data_8974,
+       },
+       {}
+ };
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -87,6 +87,6 @@ void compute_intercept_slope(struct tsen
+ int init_common(struct tsens_device *);
+ int get_temp_common(struct tsens_device *, int, int *);
+-extern const struct tsens_data data_8916;
++extern const struct tsens_data data_8916, data_8974;
+ #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq806x/patches-4.4/015-4-thermal-qcom-tsens-8960-Add-support-for-8960-family-of-SoCs.patch b/target/linux/ipq806x/patches-4.4/015-4-thermal-qcom-tsens-8960-Add-support-for-8960-family-of-SoCs.patch
new file mode 100644 (file)
index 0000000..05490cd
--- /dev/null
@@ -0,0 +1,364 @@
+From 20d4fd84bf524ad91e2cc3e4ab4020c27cfc0081 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Thu, 5 May 2016 14:21:43 +0530
+Subject: thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
+
+8960 family of SoCs have the TSENS device as part of GCC, hence
+the driver probes the virtual child device created by GCC and
+uses the parent to extract all DT properties and reuses the GCC
+regmap.
+
+Also GCC/TSENS are part of a  domain thats not always ON.
+Hence add .suspend and .resume hooks to save and restore some of
+the inited register context.
+
+Also 8960 family have some of the TSENS init sequence thats
+required to be done by the HLOS driver (some later versions of TSENS
+do not export these registers to non-secure world, and hence need
+these initializations to be done by secure bootloaders)
+
+8660 from the same family has just one sensor and hence some register
+offset/layout differences which need special handling in the driver.
+
+Based on the original code from Siddartha Mohanadoss, Stephen Boyd and
+Narendran Rajan.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ drivers/thermal/qcom/Makefile     |   2 +-
+ drivers/thermal/qcom/tsens-8960.c | 292 ++++++++++++++++++++++++++++++++++++++
+ drivers/thermal/qcom/tsens.c      |   8 +-
+ drivers/thermal/qcom/tsens.h      |   2 +-
+ 4 files changed, 298 insertions(+), 6 deletions(-)
+ create mode 100644 drivers/thermal/qcom/tsens-8960.c
+
+--- a/drivers/thermal/qcom/Makefile
++++ b/drivers/thermal/qcom/Makefile
+@@ -1,2 +1,2 @@
+ obj-$(CONFIG_QCOM_TSENS)      += qcom_tsens.o
+-qcom_tsens-y                  += tsens.o tsens-common.o tsens-8916.o tsens-8974.o
++qcom_tsens-y                  += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens-8960.c
+@@ -0,0 +1,292 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * 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/platform_device.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/regmap.h>
++#include <linux/thermal.h>
++#include "tsens.h"
++
++#define CAL_MDEGC             30000
++
++#define CONFIG_ADDR           0x3640
++#define CONFIG_ADDR_8660      0x3620
++/* CONFIG_ADDR bitmasks */
++#define CONFIG                        0x9b
++#define CONFIG_MASK           0xf
++#define CONFIG_8660           1
++#define CONFIG_SHIFT_8660     28
++#define CONFIG_MASK_8660      (3 << CONFIG_SHIFT_8660)
++
++#define STATUS_CNTL_ADDR_8064 0x3660
++#define CNTL_ADDR             0x3620
++/* CNTL_ADDR bitmasks */
++#define EN                    BIT(0)
++#define SW_RST                        BIT(1)
++#define SENSOR0_EN            BIT(3)
++#define SLP_CLK_ENA           BIT(26)
++#define SLP_CLK_ENA_8660      BIT(24)
++#define MEASURE_PERIOD                1
++#define SENSOR0_SHIFT         3
++
++/* INT_STATUS_ADDR bitmasks */
++#define MIN_STATUS_MASK               BIT(0)
++#define LOWER_STATUS_CLR      BIT(1)
++#define UPPER_STATUS_CLR      BIT(2)
++#define MAX_STATUS_MASK               BIT(3)
++
++#define THRESHOLD_ADDR                0x3624
++/* THRESHOLD_ADDR bitmasks */
++#define THRESHOLD_MAX_LIMIT_SHIFT     24
++#define THRESHOLD_MIN_LIMIT_SHIFT     16
++#define THRESHOLD_UPPER_LIMIT_SHIFT   8
++#define THRESHOLD_LOWER_LIMIT_SHIFT   0
++
++/* Initial temperature threshold values */
++#define LOWER_LIMIT_TH                0x50
++#define UPPER_LIMIT_TH                0xdf
++#define MIN_LIMIT_TH          0x0
++#define MAX_LIMIT_TH          0xff
++
++#define S0_STATUS_ADDR                0x3628
++#define INT_STATUS_ADDR               0x363c
++#define TRDY_MASK             BIT(7)
++#define TIMEOUT_US            100
++
++static int suspend_8960(struct tsens_device *tmdev)
++{
++      int ret;
++      unsigned int mask;
++      struct regmap *map = tmdev->map;
++
++      ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
++      if (ret)
++              return ret;
++
++      ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
++      if (ret)
++              return ret;
++
++      if (tmdev->num_sensors > 1)
++              mask = SLP_CLK_ENA | EN;
++      else
++              mask = SLP_CLK_ENA_8660 | EN;
++
++      ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static int resume_8960(struct tsens_device *tmdev)
++{
++      int ret;
++      struct regmap *map = tmdev->map;
++
++      ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
++      if (ret)
++              return ret;
++
++      /*
++       * Separate CONFIG restore is not needed only for 8660 as
++       * config is part of CTRL Addr and its restored as such
++       */
++      if (tmdev->num_sensors > 1) {
++              ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
++              if (ret)
++                      return ret;
++      }
++
++      ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
++      if (ret)
++              return ret;
++
++      ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static int enable_8960(struct tsens_device *tmdev, int id)
++{
++      int ret;
++      u32 reg, mask;
++
++      ret = regmap_read(tmdev->map, CNTL_ADDR, &reg);
++      if (ret)
++              return ret;
++
++      mask = BIT(id + SENSOR0_SHIFT);
++      ret = regmap_write(tmdev->map, CNTL_ADDR, reg | SW_RST);
++      if (ret)
++              return ret;
++
++      if (tmdev->num_sensors > 1)
++              reg |= mask | SLP_CLK_ENA | EN;
++      else
++              reg |= mask | SLP_CLK_ENA_8660 | EN;
++
++      ret = regmap_write(tmdev->map, CNTL_ADDR, reg);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static void disable_8960(struct tsens_device *tmdev)
++{
++      int ret;
++      u32 reg_cntl;
++      u32 mask;
++
++      mask = GENMASK(tmdev->num_sensors - 1, 0);
++      mask <<= SENSOR0_SHIFT;
++      mask |= EN;
++
++      ret = regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
++      if (ret)
++              return;
++
++      reg_cntl &= ~mask;
++
++      if (tmdev->num_sensors > 1)
++              reg_cntl &= ~SLP_CLK_ENA;
++      else
++              reg_cntl &= ~SLP_CLK_ENA_8660;
++
++      regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++}
++
++static int init_8960(struct tsens_device *tmdev)
++{
++      int ret, i;
++      u32 reg_cntl;
++
++      tmdev->map = dev_get_regmap(tmdev->dev, NULL);
++      if (!tmdev->map)
++              return -ENODEV;
++
++      /*
++       * The status registers for each sensor are discontiguous
++       * because some SoCs have 5 sensors while others have more
++       * but the control registers stay in the same place, i.e
++       * directly after the first 5 status registers.
++       */
++      for (i = 0; i < tmdev->num_sensors; i++) {
++              if (i >= 5)
++                      tmdev->sensor[i].status = S0_STATUS_ADDR + 40;
++              tmdev->sensor[i].status += i * 4;
++      }
++
++      reg_cntl = SW_RST;
++      ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
++      if (ret)
++              return ret;
++
++      if (tmdev->num_sensors > 1) {
++              reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
++              reg_cntl &= ~SW_RST;
++              ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
++                                       CONFIG_MASK, CONFIG);
++      } else {
++              reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
++              reg_cntl &= ~CONFIG_MASK_8660;
++              reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
++      }
++
++      reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
++      ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++      if (ret)
++              return ret;
++
++      reg_cntl |= EN;
++      ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++      if (ret)
++              return ret;
++
++      return 0;
++}
++
++static int calibrate_8960(struct tsens_device *tmdev)
++{
++      int i;
++      char *data;
++
++      ssize_t num_read = tmdev->num_sensors;
++      struct tsens_sensor *s = tmdev->sensor;
++
++      data = qfprom_read(tmdev->dev, "calib");
++      if (IS_ERR(data))
++              data = qfprom_read(tmdev->dev, "calib_backup");
++      if (IS_ERR(data))
++              return PTR_ERR(data);
++
++      for (i = 0; i < num_read; i++, s++)
++              s->offset = data[i];
++
++      return 0;
++}
++
++/* Temperature on y axis and ADC-code on x-axis */
++static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
++{
++      int slope, offset;
++
++      slope = thermal_zone_get_slope(s->tzd);
++      offset = CAL_MDEGC - slope * s->offset;
++
++      return adc_code * slope + offset;
++}
++
++static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp)
++{
++      int ret;
++      u32 code, trdy;
++      const struct tsens_sensor *s = &tmdev->sensor[id];
++      unsigned long timeout;
++
++      timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
++      do {
++              ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
++              if (ret)
++                      return ret;
++              if (!(trdy & TRDY_MASK))
++                      continue;
++              ret = regmap_read(tmdev->map, s->status, &code);
++              if (ret)
++                      return ret;
++              *temp = code_to_mdegC(code, s);
++              return 0;
++      } while (time_before(jiffies, timeout));
++
++      return -ETIMEDOUT;
++}
++
++const struct tsens_ops ops_8960 = {
++      .init           = init_8960,
++      .calibrate      = calibrate_8960,
++      .get_temp       = get_temp_8960,
++      .enable         = enable_8960,
++      .disable        = disable_8960,
++      .suspend        = suspend_8960,
++      .resume         = resume_8960,
++};
++
++const struct tsens_data data_8960 = {
++      .num_sensors    = 11,
++      .ops            = &ops_8960,
++};
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -122,10 +122,10 @@ static int tsens_probe(struct platform_d
+       np = dev->of_node;
+       id = of_match_node(tsens_table, np);
+-      if (!id)
+-              return -EINVAL;
+-
+-      data = id->data;
++      if (id)
++              data = id->data;
++      else
++              data = &data_8960;
+       if (data->num_sensors <= 0) {
+               dev_err(dev, "invalid number of sensors\n");
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -87,6 +87,6 @@ void compute_intercept_slope(struct tsen
+ int init_common(struct tsens_device *);
+ int get_temp_common(struct tsens_device *, int, int *);
+-extern const struct tsens_data data_8916, data_8974;
++extern const struct tsens_data data_8916, data_8974, data_8960;
+ #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq806x/patches-4.4/015-8-qcom-tsens-8916-mark-PM-functions-__maybe_unused.patch b/target/linux/ipq806x/patches-4.4/015-8-qcom-tsens-8916-mark-PM-functions-__maybe_unused.patch
new file mode 100644 (file)
index 0000000..39d2173
--- /dev/null
@@ -0,0 +1,46 @@
+From 5b97469a55872a30a0d53a1279a8ae8b1c68b52c Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 4 Jul 2016 15:12:28 +0200
+Subject: thermal: qcom: tsens-8916: mark PM functions __maybe_unused
+
+The newly added tsens-8916 driver produces warnings when CONFIG_PM
+is disabled:
+
+drivers/thermal/qcom/tsens.c:53:12: error: 'tsens_resume' defined but not used [-Werror=unused-function]
+ static int tsens_resume(struct device *dev)
+            ^~~~~~~~~~~~
+drivers/thermal/qcom/tsens.c:43:12: error: 'tsens_suspend' defined but not used [-Werror=unused-function]
+ static int tsens_suspend(struct device *dev)
+            ^~~~~~~~~~~~~
+
+This marks both functions __maybe_unused to let the compiler
+know that they might be used in other configurations, without
+adding ugly #ifdef logic.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ drivers/thermal/qcom/tsens.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -40,7 +40,7 @@ static int tsens_get_trend(void *data, l
+       return -ENOTSUPP;
+ }
+-static int tsens_suspend(struct device *dev)
++static int  __maybe_unused tsens_suspend(struct device *dev)
+ {
+       struct tsens_device *tmdev = dev_get_drvdata(dev);
+@@ -50,7 +50,7 @@ static int tsens_suspend(struct device *
+       return 0;
+ }
+-static int tsens_resume(struct device *dev)
++static int __maybe_unused tsens_resume(struct device *dev)
+ {
+       struct tsens_device *tmdev = dev_get_drvdata(dev);
diff --git a/target/linux/ipq806x/patches-4.4/016-2-thermal-of-thermal-Add-devm-version-of.patch b/target/linux/ipq806x/patches-4.4/016-2-thermal-of-thermal-Add-devm-version-of.patch
new file mode 100644 (file)
index 0000000..1ca7326
--- /dev/null
@@ -0,0 +1,143 @@
+From e498b4984db82b4ba3ceea7dba813222a31e9c2e Mon Sep 17 00:00:00 2001
+From: Laxman Dewangan <ldewangan@nvidia.com>
+Date: Wed, 9 Mar 2016 18:40:06 +0530
+Subject: thermal: of-thermal: Add devm version of
+ thermal_zone_of_sensor_register
+
+Add resource managed version of thermal_zone_of_sensor_register() and
+thermal_zone_of_sensor_unregister().
+
+This helps in reducing the code size in error path, remove of
+driver remove callbacks and making proper sequence for deallocations.
+
+Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+---
+ drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/thermal.h      | 18 ++++++++++
+ 2 files changed, 99 insertions(+)
+
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -559,6 +559,87 @@ void thermal_zone_of_sensor_unregister(s
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
++static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
++{
++      thermal_zone_of_sensor_unregister(dev,
++                                        *(struct thermal_zone_device **)res);
++}
++
++static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,
++                                           void *data)
++{
++      struct thermal_zone_device **r = res;
++
++      if (WARN_ON(!r || !*r))
++              return 0;
++
++      return *r == data;
++}
++
++/**
++ * devm_thermal_zone_of_sensor_register - Resource managed version of
++ *                            thermal_zone_of_sensor_register()
++ * @dev: a valid struct device pointer of a sensor device. Must contain
++ *       a valid .of_node, for the sensor node.
++ * @sensor_id: a sensor identifier, in case the sensor IP has more
++ *           than one sensors
++ * @data: a private pointer (owned by the caller) that will be passed
++ *      back, when a temperature reading is needed.
++ * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
++ *
++ * Refer thermal_zone_of_sensor_register() for more details.
++ *
++ * Return: On success returns a valid struct thermal_zone_device,
++ * otherwise, it returns a corresponding ERR_PTR(). Caller must
++ * check the return value with help of IS_ERR() helper.
++ * Registered hermal_zone_device device will automatically be
++ * released when device is unbounded.
++ */
++struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
++      struct device *dev, int sensor_id,
++      void *data, const struct thermal_zone_of_device_ops *ops)
++{
++      struct thermal_zone_device **ptr, *tzd;
++
++      ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),
++                         GFP_KERNEL);
++      if (!ptr)
++              return ERR_PTR(-ENOMEM);
++
++      tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);
++      if (IS_ERR(tzd)) {
++              devres_free(ptr);
++              return tzd;
++      }
++
++      *ptr = tzd;
++      devres_add(dev, ptr);
++
++      return tzd;
++}
++EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);
++
++/**
++ * devm_thermal_zone_of_sensor_unregister - Resource managed version of
++ *                            thermal_zone_of_sensor_unregister().
++ * @dev: Device for which which resource was allocated.
++ * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
++ *
++ * This function removes the sensor callbacks and private data from the
++ * thermal zone device registered with devm_thermal_zone_of_sensor_register()
++ * API. It will also silent the zone by remove the .get_temp() and .get_trend()
++ * thermal zone device callbacks.
++ * Normally this function will not need to be called and the resource
++ * management code will ensure that the resource is freed.
++ */
++void devm_thermal_zone_of_sensor_unregister(struct device *dev,
++                                          struct thermal_zone_device *tzd)
++{
++      WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,
++                             devm_thermal_zone_of_sensor_match, tzd));
++}
++EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
++
+ /***   functions parsing device tree nodes   ***/
+ /**
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -364,6 +364,11 @@ thermal_zone_of_sensor_register(struct d
+                               const struct thermal_zone_of_device_ops *ops);
+ void thermal_zone_of_sensor_unregister(struct device *dev,
+                                      struct thermal_zone_device *tz);
++struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
++              struct device *dev, int id, void *data,
++              const struct thermal_zone_of_device_ops *ops);
++void devm_thermal_zone_of_sensor_unregister(struct device *dev,
++                                          struct thermal_zone_device *tz);
+ #else
+ static inline struct thermal_zone_device *
+ thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
+@@ -378,6 +383,19 @@ void thermal_zone_of_sensor_unregister(s
+ {
+ }
++static inline struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
++              struct device *dev, int id, void *data,
++              const struct thermal_zone_of_device_ops *ops)
++{
++      return ERR_PTR(-ENODEV);
++}
++
++static inline
++void devm_thermal_zone_of_sensor_unregister(struct device *dev,
++                                          struct thermal_zone_device *tz)
++{
++}
++
+ #endif
+ #if IS_ENABLED(CONFIG_THERMAL)
diff --git a/target/linux/ipq806x/patches-4.4/017-09-thermal-core-export-apis-to-get-slope-and-offset.patch b/target/linux/ipq806x/patches-4.4/017-09-thermal-core-export-apis-to-get-slope-and-offset.patch
new file mode 100644 (file)
index 0000000..3fbe5f5
--- /dev/null
@@ -0,0 +1,101 @@
+From 4a7069a32c99a81950de035535b0a064dcceaeba Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@codeaurora.org>
+Date: Thu, 5 May 2016 14:21:42 +0530
+Subject: [PATCH] thermal: core: export apis to get slope and offset
+
+Add apis for platform thermal drivers to query for slope and offset
+attributes, which might be needed for temperature calculations.
+
+Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
+Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+---
+ Documentation/thermal/sysfs-api.txt | 12 ++++++++++++
+ drivers/thermal/thermal_core.c      | 30 ++++++++++++++++++++++++++++++
+ include/linux/thermal.h             |  8 ++++++++
+ 3 files changed, 50 insertions(+)
+
+--- a/Documentation/thermal/sysfs-api.txt
++++ b/Documentation/thermal/sysfs-api.txt
+@@ -72,6 +72,18 @@ temperature) and throttle appropriate de
+     It deletes the corresponding entry form /sys/class/thermal folder and
+     unbind all the thermal cooling devices it uses.
++1.1.7 int thermal_zone_get_slope(struct thermal_zone_device *tz)
++
++      This interface is used to read the slope attribute value
++      for the thermal zone device, which might be useful for platform
++      drivers for temperature calculations.
++
++1.1.8 int thermal_zone_get_offset(struct thermal_zone_device *tz)
++
++      This interface is used to read the offset attribute value
++      for the thermal zone device, which might be useful for platform
++      drivers for temperature calculations.
++
+ 1.2 thermal cooling device interface
+ 1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
+               void *devdata, struct thermal_cooling_device_ops *)
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -2061,6 +2061,36 @@ exit:
+ }
+ EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
++/**
++ * thermal_zone_get_slope - return the slope attribute of the thermal zone
++ * @tz: thermal zone device with the slope attribute
++ *
++ * Return: If the thermal zone device has a slope attribute, return it, else
++ * return 1.
++ */
++int thermal_zone_get_slope(struct thermal_zone_device *tz)
++{
++      if (tz && tz->tzp)
++              return tz->tzp->slope;
++      return 1;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
++
++/**
++ * thermal_zone_get_offset - return the offset attribute of the thermal zone
++ * @tz: thermal zone device with the offset attribute
++ *
++ * Return: If the thermal zone device has a offset attribute, return it, else
++ * return 0.
++ */
++int thermal_zone_get_offset(struct thermal_zone_device *tz)
++{
++      if (tz && tz->tzp)
++              return tz->tzp->offset;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(thermal_zone_get_offset);
++
+ #ifdef CONFIG_NET
+ static const struct genl_multicast_group thermal_event_mcgrps[] = {
+       { .name = THERMAL_GENL_MCAST_GROUP_NAME, },
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -432,6 +432,8 @@ thermal_of_cooling_device_register(struc
+ void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
+ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
++int thermal_zone_get_slope(struct thermal_zone_device *tz);
++int thermal_zone_get_offset(struct thermal_zone_device *tz);
+ int get_tz_trend(struct thermal_zone_device *, int);
+ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
+@@ -489,6 +491,12 @@ static inline struct thermal_zone_device
+ static inline int thermal_zone_get_temp(
+               struct thermal_zone_device *tz, int *temp)
+ { return -ENODEV; }
++static inline int thermal_zone_get_slope(
++              struct thermal_zone_device *tz)
++{ return -ENODEV; }
++static inline int thermal_zone_get_offset(
++              struct thermal_zone_device *tz)
++{ return -ENODEV; }
+ static inline int get_tz_trend(struct thermal_zone_device *tz, int trip)
+ { return -ENODEV; }
+ static inline struct thermal_instance *
diff --git a/target/linux/ipq806x/patches-4.4/019-1-nvmem-core-return-error-for-non-word-aligned-access.patch b/target/linux/ipq806x/patches-4.4/019-1-nvmem-core-return-error-for-non-word-aligned-access.patch
new file mode 100644 (file)
index 0000000..13415f5
--- /dev/null
@@ -0,0 +1,42 @@
+From 313a72ff983cc2e00ac4dcb791d40ebf2f9d5718 Mon Sep 17 00:00:00 2001
+From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Date: Tue, 17 Nov 2015 09:12:41 +0000
+Subject: nvmem: core: return error for non word aligned access
+
+nvmem providers have restrictions on register strides, so return error
+when users attempt to read/write buffers with sizes which are less
+than word size.
+
+Without this patch the userspace would continue to try as it does not
+get any error from the nvmem core, resulting in a hang or endless loop
+in userspace.
+
+Reported-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struc
+       if (pos >= nvmem->size)
+               return 0;
++      if (count < nvmem->word_size)
++              return -EINVAL;
++
+       if (pos + count > nvmem->size)
+               count = nvmem->size - pos;
+@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(stru
+       if (pos >= nvmem->size)
+               return 0;
++      if (count < nvmem->word_size)
++              return -EINVAL;
++
+       if (pos + count > nvmem->size)
+               count = nvmem->size - pos;
diff --git a/target/linux/ipq806x/patches-4.4/019-2-nvmem-core-fix-error-path-in-nvmem_add_cells.patch b/target/linux/ipq806x/patches-4.4/019-2-nvmem-core-fix-error-path-in-nvmem_add_cells.patch
new file mode 100644 (file)
index 0000000..1f9473b
--- /dev/null
@@ -0,0 +1,34 @@
+From dfdf141429f0895b63c882facc42c86f225033cb Mon Sep 17 00:00:00 2001
+From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Date: Mon, 8 Feb 2016 22:04:29 +0100
+Subject: nvmem: core: fix error path in nvmem_add_cells()
+
+The current code fails to nvmem_cell_drop(cells[0]) - even worse, if
+the loop above fails already at i==0, we'll enter an essentially
+infinite loop doing nvmem_cell_drop on cells[-1], cells[-2], ... which
+is unlikely to end well.
+
+Also, we're not freeing the temporary backing array cells on the error
+path.
+
+Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -294,9 +294,11 @@ static int nvmem_add_cells(struct nvmem_
+       return 0;
+ err:
+-      while (--i)
++      while (i--)
+               nvmem_cell_drop(cells[i]);
++      kfree(cells);
++
+       return rval;
+ }
diff --git a/target/linux/ipq806x/patches-4.4/019-3-nvmem-Add-flag-to-export-NVMEM-to-root-only.patch b/target/linux/ipq806x/patches-4.4/019-3-nvmem-Add-flag-to-export-NVMEM-to-root-only.patch
new file mode 100644 (file)
index 0000000..77136ea
--- /dev/null
@@ -0,0 +1,101 @@
+From 811b0d6538b9f26f3eb0f90fe4e6118f2480ec6f Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Fri, 26 Feb 2016 20:59:18 +0100
+Subject: nvmem: Add flag to export NVMEM to root only
+
+Legacy AT24, AT25 EEPROMs are exported in sys so that only root can
+read the contents. The EEPROMs may contain sensitive information. Add
+a flag so the provide can indicate that NVMEM should also restrict
+access to root only.
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c           | 57 ++++++++++++++++++++++++++++++++++++++++--
+ include/linux/nvmem-provider.h |  1 +
+ 2 files changed, 56 insertions(+), 2 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -161,6 +161,53 @@ static const struct attribute_group *nvm
+       NULL,
+ };
++/* default read/write permissions, root only */
++static struct bin_attribute bin_attr_rw_root_nvmem = {
++      .attr   = {
++              .name   = "nvmem",
++              .mode   = S_IWUSR | S_IRUSR,
++      },
++      .read   = bin_attr_nvmem_read,
++      .write  = bin_attr_nvmem_write,
++};
++
++static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
++      &bin_attr_rw_root_nvmem,
++      NULL,
++};
++
++static const struct attribute_group nvmem_bin_rw_root_group = {
++      .bin_attrs      = nvmem_bin_rw_root_attributes,
++};
++
++static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
++      &nvmem_bin_rw_root_group,
++      NULL,
++};
++
++/* read only permission, root only */
++static struct bin_attribute bin_attr_ro_root_nvmem = {
++      .attr   = {
++              .name   = "nvmem",
++              .mode   = S_IRUSR,
++      },
++      .read   = bin_attr_nvmem_read,
++};
++
++static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
++      &bin_attr_ro_root_nvmem,
++      NULL,
++};
++
++static const struct attribute_group nvmem_bin_ro_root_group = {
++      .bin_attrs      = nvmem_bin_ro_root_attributes,
++};
++
++static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
++      &nvmem_bin_ro_root_group,
++      NULL,
++};
++
+ static void nvmem_release(struct device *dev)
+ {
+       struct nvmem_device *nvmem = to_nvmem_device(dev);
+@@ -355,8 +402,14 @@ struct nvmem_device *nvmem_register(cons
+       nvmem->read_only = of_property_read_bool(np, "read-only") |
+                          config->read_only;
+-      nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups :
+-                                             nvmem_rw_dev_groups;
++      if (config->root_only)
++              nvmem->dev.groups = nvmem->read_only ?
++                      nvmem_ro_root_dev_groups :
++                      nvmem_rw_root_dev_groups;
++      else
++              nvmem->dev.groups = nvmem->read_only ?
++                      nvmem_ro_dev_groups :
++                      nvmem_rw_dev_groups;
+       device_initialize(&nvmem->dev);
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -23,6 +23,7 @@ struct nvmem_config {
+       const struct nvmem_cell_info    *cells;
+       int                     ncells;
+       bool                    read_only;
++      bool                    root_only;
+ };
+ #if IS_ENABLED(CONFIG_NVMEM)
diff --git a/target/linux/ipq806x/patches-4.4/019-4-nvmem-Add-backwards-compatibility-support-for-older-EEPROM-drivers.patch b/target/linux/ipq806x/patches-4.4/019-4-nvmem-Add-backwards-compatibility-support-for-older-EEPROM-drivers.patch
new file mode 100644 (file)
index 0000000..6344d0e
--- /dev/null
@@ -0,0 +1,181 @@
+From b6c217ab9be6895384cf0b284ace84ad79e5c53b Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Fri, 26 Feb 2016 20:59:19 +0100
+Subject: nvmem: Add backwards compatibility support for older EEPROM drivers.
+
+Older drivers made an 'eeprom' file available in the /sys device
+directory. Have the NVMEM core provide this to retain backwards
+compatibility.
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/core.c           | 84 ++++++++++++++++++++++++++++++++++++++----
+ include/linux/nvmem-provider.h |  4 +-
+ 2 files changed, 79 insertions(+), 9 deletions(-)
+
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -38,8 +38,13 @@ struct nvmem_device {
+       int                     users;
+       size_t                  size;
+       bool                    read_only;
++      int                     flags;
++      struct bin_attribute    eeprom;
++      struct device           *base_dev;
+ };
++#define FLAG_COMPAT           BIT(0)
++
+ struct nvmem_cell {
+       const char              *name;
+       int                     offset;
+@@ -56,16 +61,26 @@ static DEFINE_IDA(nvmem_ida);
+ static LIST_HEAD(nvmem_cells);
+ static DEFINE_MUTEX(nvmem_cells_mutex);
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++static struct lock_class_key eeprom_lock_key;
++#endif
++
+ #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
+ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
+                                   struct bin_attribute *attr,
+                                   char *buf, loff_t pos, size_t count)
+ {
+-      struct device *dev = container_of(kobj, struct device, kobj);
+-      struct nvmem_device *nvmem = to_nvmem_device(dev);
++      struct device *dev;
++      struct nvmem_device *nvmem;
+       int rc;
++      if (attr->private)
++              dev = attr->private;
++      else
++              dev = container_of(kobj, struct device, kobj);
++      nvmem = to_nvmem_device(dev);
++
+       /* Stop the user from reading */
+       if (pos >= nvmem->size)
+               return 0;
+@@ -90,10 +105,16 @@ static ssize_t bin_attr_nvmem_write(stru
+                                    struct bin_attribute *attr,
+                                    char *buf, loff_t pos, size_t count)
+ {
+-      struct device *dev = container_of(kobj, struct device, kobj);
+-      struct nvmem_device *nvmem = to_nvmem_device(dev);
++      struct device *dev;
++      struct nvmem_device *nvmem;
+       int rc;
++      if (attr->private)
++              dev = attr->private;
++      else
++              dev = container_of(kobj, struct device, kobj);
++      nvmem = to_nvmem_device(dev);
++
+       /* Stop the user from writing */
+       if (pos >= nvmem->size)
+               return 0;
+@@ -349,6 +370,43 @@ err:
+       return rval;
+ }
++/*
++ * nvmem_setup_compat() - Create an additional binary entry in
++ * drivers sys directory, to be backwards compatible with the older
++ * drivers/misc/eeprom drivers.
++ */
++static int nvmem_setup_compat(struct nvmem_device *nvmem,
++                            const struct nvmem_config *config)
++{
++      int rval;
++
++      if (!config->base_dev)
++              return -EINVAL;
++
++      if (nvmem->read_only)
++              nvmem->eeprom = bin_attr_ro_root_nvmem;
++      else
++              nvmem->eeprom = bin_attr_rw_root_nvmem;
++      nvmem->eeprom.attr.name = "eeprom";
++      nvmem->eeprom.size = nvmem->size;
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++      nvmem->eeprom.attr.key = &eeprom_lock_key;
++#endif
++      nvmem->eeprom.private = &nvmem->dev;
++      nvmem->base_dev = config->base_dev;
++
++      rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
++      if (rval) {
++              dev_err(&nvmem->dev,
++                      "Failed to create eeprom binary file %d\n", rval);
++              return rval;
++      }
++
++      nvmem->flags |= FLAG_COMPAT;
++
++      return 0;
++}
++
+ /**
+  * nvmem_register() - Register a nvmem device for given nvmem_config.
+  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
+@@ -416,16 +474,23 @@ struct nvmem_device *nvmem_register(cons
+       dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
+       rval = device_add(&nvmem->dev);
+-      if (rval) {
+-              ida_simple_remove(&nvmem_ida, nvmem->id);
+-              kfree(nvmem);
+-              return ERR_PTR(rval);
++      if (rval)
++              goto out;
++
++      if (config->compat) {
++              rval = nvmem_setup_compat(nvmem, config);
++              if (rval)
++                      goto out;
+       }
+       if (config->cells)
+               nvmem_add_cells(nvmem, config);
+       return nvmem;
++out:
++      ida_simple_remove(&nvmem_ida, nvmem->id);
++      kfree(nvmem);
++      return ERR_PTR(rval);
+ }
+ EXPORT_SYMBOL_GPL(nvmem_register);
+@@ -445,6 +510,9 @@ int nvmem_unregister(struct nvmem_device
+       }
+       mutex_unlock(&nvmem_mutex);
++      if (nvmem->flags & FLAG_COMPAT)
++              device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
++
+       nvmem_device_remove_all_cells(nvmem);
+       device_del(&nvmem->dev);
+--- a/include/linux/nvmem-provider.h
++++ b/include/linux/nvmem-provider.h
+@@ -24,6 +24,9 @@ struct nvmem_config {
+       int                     ncells;
+       bool                    read_only;
+       bool                    root_only;
++      /* To be only used by old driver/misc/eeprom drivers */
++      bool                    compat;
++      struct device           *base_dev;
+ };
+ #if IS_ENABLED(CONFIG_NVMEM)
+@@ -44,5 +47,4 @@ static inline int nvmem_unregister(struc
+ }
+ #endif /* CONFIG_NVMEM */
+-
+ #endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */
diff --git a/target/linux/ipq806x/patches-4.4/309-clk-gcc-add-tsens-child-node.patch b/target/linux/ipq806x/patches-4.4/309-clk-gcc-add-tsens-child-node.patch
new file mode 100644 (file)
index 0000000..0eae3e7
--- /dev/null
@@ -0,0 +1,38 @@
+From 856371ca1561ca9b3280cc323ff296c7c5e1fa93 Mon Sep 17 00:00:00 2001
+From: Pavel Kubelun <be.dissent@gmail.com>
+Date: Tue, 22 Nov 2016 17:37:56 +0300
+Subject: [PATCH] ipq806x: clk: gcc: add tsens child node
+
+Thermal sensors in ipq806x are inside a Global clock controller.
+Add a child node into it to be used by the TSENS driver.
+
+Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
+
+---
+ drivers/clk/qcom/gcc-ipq806x.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/clk/qcom/gcc-ipq806x.c
++++ b/drivers/clk/qcom/gcc-ipq806x.c
+@@ -3109,6 +3109,7 @@ MODULE_DEVICE_TABLE(of, gcc_ipq806x_matc
+ static int gcc_ipq806x_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
++      struct platform_device *tsens;
+       struct regmap *regmap;
+       int ret;
+@@ -3138,6 +3139,13 @@ static int gcc_ipq806x_probe(struct plat
+       regmap_write(regmap, 0x3cf8, 8);
+       regmap_write(regmap, 0x3d18, 8);
++      tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
++                                            NULL, 0);
++      if (IS_ERR(tsens))
++              return PTR_ERR(tsens);
++
++      platform_set_drvdata(pdev, tsens);
++
+       return 0;
+ }
diff --git a/target/linux/ipq806x/patches-4.4/310-add-necessary-thermal-data.patch b/target/linux/ipq806x/patches-4.4/310-add-necessary-thermal-data.patch
new file mode 100644 (file)
index 0000000..b2564a5
--- /dev/null
@@ -0,0 +1,150 @@
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -31,6 +31,9 @@
+                       clock-latency = <100000>;
+                       cpu-supply = <&smb208_s2a>;
+                       voltage-tolerance = <5>;
++                      cooling-min-state = <0>;
++                      cooling-max-state = <10>;
++                      #cooling-cells = <2>;
+                       cpu-idle-states = <&CPU_SPC>;
+               };
+@@ -46,6 +49,9 @@
+                       clock-names = "cpu", "l2";
+                       clock-latency = <100000>;
+                       cpu-supply = <&smb208_s2b>;
++                      cooling-min-state = <0>;
++                      cooling-max-state = <10>;
++                      #cooling-cells = <2>;
+                       cpu-idle-states = <&CPU_SPC>;
+               };
+@@ -70,6 +76,92 @@
+               };
+       };
++      thermal-zones {
++              cpu-thermal0 {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&gcc 5>;
++                      coefficients = <1132 0>;
++
++                      trips {
++                              cpu_alert0: trip0 {
++                                      temperature = <75000>;
++                                      hysteresis = <2000>;
++                                      type = "passive";
++                              };
++                              cpu_crit0: trip1 {
++                                      temperature = <110000>;
++                                      hysteresis = <2000>;
++                                      type = "critical";
++                              };
++                      };
++              };
++
++              cpu-thermal1 {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&gcc 6>;
++                      coefficients = <1132 0>;
++
++                      trips {
++                              cpu_alert1: trip0 {
++                                      temperature = <75000>;
++                                      hysteresis = <2000>;
++                                      type = "passive";
++                              };
++                              cpu_crit1: trip1 {
++                                      temperature = <110000>;
++                                      hysteresis = <2000>;
++                                      type = "critical";
++                              };
++                      };
++              };
++
++              cpu-thermal2 {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&gcc 7>;
++                      coefficients = <1199 0>;
++
++                      trips {
++                              cpu_alert2: trip0 {
++                                      temperature = <75000>;
++                                      hysteresis = <2000>;
++                                      type = "passive";
++                              };
++                              cpu_crit2: trip1 {
++                                      temperature = <110000>;
++                                      hysteresis = <2000>;
++                                      type = "critical";
++                              };
++                      };
++              };
++
++              cpu-thermal3 {
++                      polling-delay-passive = <250>;
++                      polling-delay = <1000>;
++
++                      thermal-sensors = <&gcc 8>;
++                      coefficients = <1132 0>;
++
++                      trips {
++                              cpu_alert3: trip0 {
++                                      temperature = <75000>;
++                                      hysteresis = <2000>;
++                                      type = "passive";
++                              };
++                              cpu_crit3: trip1 {
++                                      temperature = <110000>;
++                                      hysteresis = <2000>;
++                                      type = "critical";
++                              };
++                      };
++              };
++      };
++
+       cpu-pmu {
+               compatible = "qcom,krait-pmu";
+               interrupts = <1 10 0x304>;
+@@ -172,6 +264,21 @@
+                       reg-names = "lpass-lpaif";
+               };
++              qfprom: qfprom@700000 {
++                      compatible = "qcom,qfprom", "syscon";
++                      reg = <0x00700000 0x1000>;
++                      #address-cells = <1>;
++                      #size-cells = <1>;
++                      ranges;
++
++                      tsens_calib: calib {
++                              reg = <0x400 0x10>;
++                      };
++                      tsens_backup: backup_calib {
++                              reg = <0x410 0x10>;
++                      };
++              };
++
+               rpm@108000 {
+                       compatible = "qcom,rpm-ipq8064";
+                       reg = <0x108000 0x1000>;
+@@ -499,8 +606,12 @@
+               gcc: clock-controller@900000 {
+                       compatible = "qcom,gcc-ipq8064";
+                       reg = <0x00900000 0x4000>;
++                      nvmem-cells = <&tsens_calib>, <&tsens_backup>;
++                      nvmem-cell-names = "calib", "calib_backup";
+                       #clock-cells = <1>;
+                       #reset-cells = <1>;
++                      #power-domain-cells = <1>;
++                      #thermal-sensor-cells = <1>;
+               };
+               tcsr: syscon@1a400000 {
index aa12121dff8d6c4329cbf43b9f31ba404323835b..f6f357253fe3d4005cf5c4768d5a6a8b27673a15 100644 (file)
@@ -121,7 +121,7 @@ Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
  };
 --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
 +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -793,6 +793,92 @@
+@@ -904,6 +904,92 @@
  
                        status = "disabled";
                };