All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-10-09  9:41 ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.

Eduardo, can you please take a look at the patches and let me
know if you see any issues.

Current set of patches apply on 4.3-rc4. Need to pull in clk-next
(for a dependent patch) to be able to test on ifc6410 board.

Changes since v3:
* Dropped 'clk: qcom: create virtual child device for TSENS' which
is picked up by Stephen
* Updated GCC bindings with optional TSENS properties

Changes since v2:
* Minor review fixes from Stephen/Punit and rebase on 4.3-rc4

Changes since v1:
* Created virtual tsens device from gcc driver for 8960,
with DT having a single node for gcc and tsens
* Minor fixes with rebasing on 4.3-rc1

Changes since RFC:
* Added support for 8916 and 8084
* Based off the latest nvmem framework patches [1]
* Minor review fixes for comments mostly from Lina

This is an attempt to have a single TSENS driver for
the different versions of the TSENS IP that exist, on
different qcom msm/apq SoCs'
Support is added for msm8916, msm8960 and msm8974 families.

A lot of the work is based of original code from Stephen Boyd
and Siddartha Mohanadoss. I have also picked some of what
Narendran Rajan did in his attempt to upstream the support
for 8960 family. I could not keep the original authorship on
any of the patches because I ended up moving the code around
quite a bit in an effort to have a single driver for the
various devices. I would be glad to change the authorship
for any of the patches if needed.

Rajendra Nayak (8):
  thermal: qcom: tsens: Add a skeletal TSENS drivers
  thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
  thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
  thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
  arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
  arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
  arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
  arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes

 .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
 .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
 arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
 arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
 arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
 drivers/thermal/Kconfig                            |   5 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/qcom/Kconfig                       |  10 +
 drivers/thermal/qcom/Makefile                      |   2 +
 drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
 drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
 drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
 drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
 drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
 drivers/thermal/qcom/tsens.h                       |  69 +++++
 16 files changed, 1490 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-8916.c
 create mode 100644 drivers/thermal/qcom/tsens-8960.c
 create mode 100644 drivers/thermal/qcom/tsens-8974.c
 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

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-10-09  9:41 ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.

Eduardo, can you please take a look at the patches and let me
know if you see any issues.

Current set of patches apply on 4.3-rc4. Need to pull in clk-next
(for a dependent patch) to be able to test on ifc6410 board.

Changes since v3:
* Dropped 'clk: qcom: create virtual child device for TSENS' which
is picked up by Stephen
* Updated GCC bindings with optional TSENS properties

Changes since v2:
* Minor review fixes from Stephen/Punit and rebase on 4.3-rc4

Changes since v1:
* Created virtual tsens device from gcc driver for 8960,
with DT having a single node for gcc and tsens
* Minor fixes with rebasing on 4.3-rc1

Changes since RFC:
* Added support for 8916 and 8084
* Based off the latest nvmem framework patches [1]
* Minor review fixes for comments mostly from Lina

This is an attempt to have a single TSENS driver for
the different versions of the TSENS IP that exist, on
different qcom msm/apq SoCs'
Support is added for msm8916, msm8960 and msm8974 families.

A lot of the work is based of original code from Stephen Boyd
and Siddartha Mohanadoss. I have also picked some of what
Narendran Rajan did in his attempt to upstream the support
for 8960 family. I could not keep the original authorship on
any of the patches because I ended up moving the code around
quite a bit in an effort to have a single driver for the
various devices. I would be glad to change the authorship
for any of the patches if needed.

Rajendra Nayak (8):
  thermal: qcom: tsens: Add a skeletal TSENS drivers
  thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
  thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
  thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
  arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
  arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
  arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
  arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes

 .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
 .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
 arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
 arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
 arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
 arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
 drivers/thermal/Kconfig                            |   5 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/qcom/Kconfig                       |  10 +
 drivers/thermal/qcom/Makefile                      |   2 +
 drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
 drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
 drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
 drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
 drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
 drivers/thermal/qcom/tsens.h                       |  69 +++++
 16 files changed, 1490 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-8916.c
 create mode 100644 drivers/thermal/qcom/tsens-8960.c
 create mode 100644 drivers/thermal/qcom/tsens-8974.c
 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

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

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>
---
 .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 ++++
 drivers/thermal/Kconfig                            |   5 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/qcom/Kconfig                       |  10 ++
 drivers/thermal/qcom/Makefile                      |   2 +
 drivers/thermal/qcom/tsens.c                       | 199 +++++++++++++++++++++
 drivers/thermal/qcom/tsens.h                       |  58 ++++++
 7 files changed, 308 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.c
 create mode 100644 drivers/thermal/qcom/tsens.h

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
new file mode 100644
index 0000000..8b1f26f
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
@@ -0,0 +1,33 @@
+* QCOM SoC Temperature Sensor (TSENS)
+
+Required properties:
+- compatible :
+ - "qcom,msm8916-tsens" : For 8916 Family of SoCs
+ - "qcom,msm8974-tsens" : For 8974 Family of SoCs
+
+- reg: Address range of the thermal registers
+- qcom,tsens-slopes : Must contain slope value for each of the sensors controlled
+			by this device
+- #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
+
+Optional properties:
+- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
+		  have a fixed number of sensors (like 11) but a given SoC can
+		  use only 5 of these and they might not always the first 5. They
+		  could be sensors 0, 1, 4, 8 and 9. This property is used to
+		  describe the subset of the sensors used. If this property is
+		  missing they are assumed to be the first 'n' sensors numbered
+		  sequentially in which case the number of sensors defaults to
+		  the number of slope values.
+
+Example:
+tsens: thermal-sensor@900000 {
+		compatible = "qcom,msm8916-tsens";
+		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+		nvmem-cell-names = "caldata", "calsel";
+		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
+		qcom,sensor-id = <0 1 2 4 5>;
+		#thermal-sensor-cells = <1>;
+	};
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5aabc4b..d49f2bd 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -374,4 +374,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
+source "drivers/thermal/qcom/Kconfig"
+endmenu
+
 endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 26f1608..cdaa55f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
 obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
 obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
 obj-$(CONFIG_ST_THERMAL)	+= st/
+obj-$(CONFIG_QCOM_TSENS)	+= qcom/
 obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
 obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
new file mode 100644
index 0000000..f7e8e40
--- /dev/null
+++ b/drivers/thermal/qcom/Kconfig
@@ -0,0 +1,10 @@
+config QCOM_TSENS
+	tristate "Qualcomm TSENS Temperature Alarm"
+	depends on THERMAL
+	depends on QCOM_QFPROM
+	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.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
new file mode 100644
index 0000000..401069b
--- /dev/null
+++ b/drivers/thermal/qcom/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
+qcom_tsens-y			+= tsens.o
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
new file mode 100644
index 0000000..87f5215
--- /dev/null
+++ b/drivers/thermal/qcom/tsens.c
@@ -0,0 +1,199 @@
+/*
+ * 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 -ENOSYS;
+}
+
+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, ret;
+	struct thermal_zone_device *tzd;
+	u32 *hw_id, n = tmdev->num_sensors;
+	struct device_node *np = tmdev->dev->of_node;
+
+	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
+	if (!hw_id)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
+	for (i = 0;  i < tmdev->num_sensors; i++) {
+		if (ret)
+			tmdev->sensor[i].hw_id = i;
+		else
+			tmdev->sensor[i].hw_id = hw_id[i];
+		tmdev->sensor[i].tmdev = tmdev;
+		tmdev->sensor[i].id = i;
+		tzd = 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, num;
+	struct device *dev;
+	struct device_node *np;
+	struct tsens_sensor *s;
+	struct tsens_device *tmdev;
+	const struct of_device_id *id;
+
+	dev = &pdev->dev;
+	np = dev->of_node;
+
+	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
+	if (num <= 0) {
+		dev_err(dev, "invalid tsens slopes\n");
+		return -EINVAL;
+	}
+
+	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
+			     num * sizeof(*s), GFP_KERNEL);
+	if (!tmdev)
+		return -ENOMEM;
+
+	tmdev->dev = dev;
+	tmdev->num_sensors = num;
+
+	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
+		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
+					   &s->slope);
+
+	id = of_match_node(tsens_table, np);
+	if (!id)
+		return -ENODEV;
+
+	tmdev->ops = id->data;
+	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
+	    !tmdev->ops->get_temp)
+		return -EINVAL;
+
+	ret = tmdev->ops->init(tmdev);
+	if (ret < 0) {
+		dev_err(dev, "tsens init failed\n");
+		return ret;
+	}
+
+	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)
+{
+	int i;
+	struct tsens_device *tmdev = platform_get_drvdata(pdev);
+	struct thermal_zone_device *tzd;
+
+	if (tmdev->ops->disable)
+		tmdev->ops->disable(tmdev);
+
+	for (i = 0; i < tmdev->num_sensors; i++) {
+		tzd = tmdev->sensor[i].tzd;
+		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
+	}
+
+	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");
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
new file mode 100644
index 0000000..f0fc353
--- /dev/null
+++ b/drivers/thermal/qcom/tsens.h
@@ -0,0 +1,58 @@
+/*
+ * 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__
+
+struct tsens_device;
+
+struct tsens_sensor {
+	struct tsens_device		*tmdev;
+	struct thermal_zone_device	*tzd;
+	int				offset;
+	int				id;
+	int				hw_id;
+	u32				slope;
+	u32				status;
+};
+
+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 *);
+};
+
+/* 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];
+};
+
+#endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 ++++
 drivers/thermal/Kconfig                            |   5 +
 drivers/thermal/Makefile                           |   1 +
 drivers/thermal/qcom/Kconfig                       |  10 ++
 drivers/thermal/qcom/Makefile                      |   2 +
 drivers/thermal/qcom/tsens.c                       | 199 +++++++++++++++++++++
 drivers/thermal/qcom/tsens.h                       |  58 ++++++
 7 files changed, 308 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.c
 create mode 100644 drivers/thermal/qcom/tsens.h

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
new file mode 100644
index 0000000..8b1f26f
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
@@ -0,0 +1,33 @@
+* QCOM SoC Temperature Sensor (TSENS)
+
+Required properties:
+- compatible :
+ - "qcom,msm8916-tsens" : For 8916 Family of SoCs
+ - "qcom,msm8974-tsens" : For 8974 Family of SoCs
+
+- reg: Address range of the thermal registers
+- qcom,tsens-slopes : Must contain slope value for each of the sensors controlled
+			by this device
+- #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
+
+Optional properties:
+- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
+		  have a fixed number of sensors (like 11) but a given SoC can
+		  use only 5 of these and they might not always the first 5. They
+		  could be sensors 0, 1, 4, 8 and 9. This property is used to
+		  describe the subset of the sensors used. If this property is
+		  missing they are assumed to be the first 'n' sensors numbered
+		  sequentially in which case the number of sensors defaults to
+		  the number of slope values.
+
+Example:
+tsens: thermal-sensor at 900000 {
+		compatible = "qcom,msm8916-tsens";
+		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+		nvmem-cell-names = "caldata", "calsel";
+		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
+		qcom,sensor-id = <0 1 2 4 5>;
+		#thermal-sensor-cells = <1>;
+	};
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5aabc4b..d49f2bd 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -374,4 +374,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
+source "drivers/thermal/qcom/Kconfig"
+endmenu
+
 endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 26f1608..cdaa55f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
 obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
 obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
 obj-$(CONFIG_ST_THERMAL)	+= st/
+obj-$(CONFIG_QCOM_TSENS)	+= qcom/
 obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
 obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
new file mode 100644
index 0000000..f7e8e40
--- /dev/null
+++ b/drivers/thermal/qcom/Kconfig
@@ -0,0 +1,10 @@
+config QCOM_TSENS
+	tristate "Qualcomm TSENS Temperature Alarm"
+	depends on THERMAL
+	depends on QCOM_QFPROM
+	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.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
new file mode 100644
index 0000000..401069b
--- /dev/null
+++ b/drivers/thermal/qcom/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
+qcom_tsens-y			+= tsens.o
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
new file mode 100644
index 0000000..87f5215
--- /dev/null
+++ b/drivers/thermal/qcom/tsens.c
@@ -0,0 +1,199 @@
+/*
+ * 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 -ENOSYS;
+}
+
+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, ret;
+	struct thermal_zone_device *tzd;
+	u32 *hw_id, n = tmdev->num_sensors;
+	struct device_node *np = tmdev->dev->of_node;
+
+	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
+	if (!hw_id)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
+	for (i = 0;  i < tmdev->num_sensors; i++) {
+		if (ret)
+			tmdev->sensor[i].hw_id = i;
+		else
+			tmdev->sensor[i].hw_id = hw_id[i];
+		tmdev->sensor[i].tmdev = tmdev;
+		tmdev->sensor[i].id = i;
+		tzd = 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, num;
+	struct device *dev;
+	struct device_node *np;
+	struct tsens_sensor *s;
+	struct tsens_device *tmdev;
+	const struct of_device_id *id;
+
+	dev = &pdev->dev;
+	np = dev->of_node;
+
+	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
+	if (num <= 0) {
+		dev_err(dev, "invalid tsens slopes\n");
+		return -EINVAL;
+	}
+
+	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
+			     num * sizeof(*s), GFP_KERNEL);
+	if (!tmdev)
+		return -ENOMEM;
+
+	tmdev->dev = dev;
+	tmdev->num_sensors = num;
+
+	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
+		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
+					   &s->slope);
+
+	id = of_match_node(tsens_table, np);
+	if (!id)
+		return -ENODEV;
+
+	tmdev->ops = id->data;
+	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
+	    !tmdev->ops->get_temp)
+		return -EINVAL;
+
+	ret = tmdev->ops->init(tmdev);
+	if (ret < 0) {
+		dev_err(dev, "tsens init failed\n");
+		return ret;
+	}
+
+	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)
+{
+	int i;
+	struct tsens_device *tmdev = platform_get_drvdata(pdev);
+	struct thermal_zone_device *tzd;
+
+	if (tmdev->ops->disable)
+		tmdev->ops->disable(tmdev);
+
+	for (i = 0; i < tmdev->num_sensors; i++) {
+		tzd = tmdev->sensor[i].tzd;
+		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
+	}
+
+	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");
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
new file mode 100644
index 0000000..f0fc353
--- /dev/null
+++ b/drivers/thermal/qcom/tsens.h
@@ -0,0 +1,58 @@
+/*
+ * 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__
+
+struct tsens_device;
+
+struct tsens_sensor {
+	struct tsens_device		*tmdev;
+	struct thermal_zone_device	*tzd;
+	int				offset;
+	int				id;
+	int				hw_id;
+	u32				slope;
+	u32				status;
+};
+
+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 *);
+};
+
+/* 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];
+};
+
+#endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

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>
---
 drivers/thermal/qcom/Makefile       |   2 +-
 drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c        |   1 +
 drivers/thermal/qcom/tsens.h        |  11 +++
 5 files changed, 250 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thermal/qcom/tsens-8916.c
 create mode 100644 drivers/thermal/qcom/tsens-common.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 401069b..05c98e4 100644
--- 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
+qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
new file mode 100644
index 0000000..a69aea3
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8916.c
@@ -0,0 +1,107 @@
+/*
+ * 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,
+};
diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
new file mode 100644
index 0000000..4acf52c
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-common.c
@@ -0,0 +1,130 @@
+/*
+ * 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/nvmem-consumer.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.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
+
+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;
+}
+
+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]);
+
+		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_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)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 87f5215..3d49293 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
 static const struct of_device_id tsens_table[] = {
 	{
 		.compatible = "qcom,msm8916-tsens",
+		.data = &ops_8916,
 	}, {
 		.compatible = "qcom,msm8974-tsens",
 	},
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index f0fc353..0923822 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -13,6 +13,10 @@
 #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 {
@@ -55,4 +59,11 @@ struct tsens_device {
 	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 *);
+
+extern const struct tsens_ops ops_8916;
+
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 drivers/thermal/qcom/Makefile       |   2 +-
 drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c        |   1 +
 drivers/thermal/qcom/tsens.h        |  11 +++
 5 files changed, 250 insertions(+), 1 deletion(-)
 create mode 100644 drivers/thermal/qcom/tsens-8916.c
 create mode 100644 drivers/thermal/qcom/tsens-common.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 401069b..05c98e4 100644
--- 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
+qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
new file mode 100644
index 0000000..a69aea3
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8916.c
@@ -0,0 +1,107 @@
+/*
+ * 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,
+};
diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
new file mode 100644
index 0000000..4acf52c
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-common.c
@@ -0,0 +1,130 @@
+/*
+ * 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/nvmem-consumer.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.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
+
+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;
+}
+
+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]);
+
+		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_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)
+		return -ENODEV;
+
+	return 0;
+}
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 87f5215..3d49293 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
 static const struct of_device_id tsens_table[] = {
 	{
 		.compatible = "qcom,msm8916-tsens",
+		.data = &ops_8916,
 	}, {
 		.compatible = "qcom,msm8974-tsens",
 	},
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index f0fc353..0923822 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -13,6 +13,10 @@
 #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 {
@@ -55,4 +59,11 @@ struct tsens_device {
 	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 *);
+
+extern const struct tsens_ops ops_8916;
+
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 3/8] thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

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>
---
 drivers/thermal/qcom/Makefile     |   2 +-
 drivers/thermal/qcom/tsens-8974.c | 239 ++++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c      |   1 +
 drivers/thermal/qcom/tsens.h      |   2 +-
 4 files changed, 242 insertions(+), 2 deletions(-)
 create mode 100644 drivers/thermal/qcom/tsens-8974.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 05c98e4..a471100 100644
--- 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
diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c
new file mode 100644
index 0000000..19d9258
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8974.c
@@ -0,0 +1,239 @@
+/*
+ * 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,
+};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 3d49293..06ed0c6 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -68,6 +68,7 @@ static const struct of_device_id tsens_table[] = {
 		.data = &ops_8916,
 	}, {
 		.compatible = "qcom,msm8974-tsens",
+		.data = &ops_8974,
 	},
 	{}
 };
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 0923822..00183db 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -64,6 +64,6 @@ 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 *);
 
-extern const struct tsens_ops ops_8916;
+extern const struct tsens_ops ops_8916, ops_8974;
 
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 3/8] thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 drivers/thermal/qcom/Makefile     |   2 +-
 drivers/thermal/qcom/tsens-8974.c | 239 ++++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c      |   1 +
 drivers/thermal/qcom/tsens.h      |   2 +-
 4 files changed, 242 insertions(+), 2 deletions(-)
 create mode 100644 drivers/thermal/qcom/tsens-8974.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 05c98e4..a471100 100644
--- 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
diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c
new file mode 100644
index 0000000..19d9258
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8974.c
@@ -0,0 +1,239 @@
+/*
+ * 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,
+};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 3d49293..06ed0c6 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -68,6 +68,7 @@ static const struct of_device_id tsens_table[] = {
 		.data = &ops_8916,
 	}, {
 		.compatible = "qcom,msm8974-tsens",
+		.data = &ops_8974,
 	},
 	{}
 };
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 0923822..00183db 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -64,6 +64,6 @@ 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 *);
 
-extern const struct tsens_ops ops_8916;
+extern const struct tsens_ops ops_8916, ops_8974;
 
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

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>
---
 drivers/thermal/qcom/Makefile     |   2 +-
 drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c      |  13 +-
 drivers/thermal/qcom/tsens.h      |   2 +-
 4 files changed, 302 insertions(+), 6 deletions(-)
 create mode 100644 drivers/thermal/qcom/tsens-8960.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index a471100..f3cefd1 100644
--- 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
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
new file mode 100644
index 0000000..00f45e7
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -0,0 +1,291 @@
+/*
+ * 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 "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)
+
+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;
+
+	tmdev->trdy = false;
+
+	return 0;
+}
+
+static int resume_8960(struct tsens_device *tmdev)
+{
+	int ret;
+	unsigned long reg_cntl;
+	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;
+
+	reg_cntl = tmdev->ctx.control;
+	reg_cntl >>= SENSOR0_SHIFT;
+
+	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;
+
+	tmdev->trdy = false;
+	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 = CAL_MDEGC - s->slope * 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)
+{
+	return adc_code * s->slope + s->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];
+
+	if (!tmdev->trdy) {
+		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+		if (ret)
+			return ret;
+		while (!(trdy & TRDY_MASK)) {
+			usleep_range(1000, 1100);
+			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+		}
+		tmdev->trdy = true;
+	}
+
+	ret = regmap_read(tmdev->map, s->status, &code);
+	if (ret)
+		return ret;
+
+	*temp = code_to_mdegC(code, s);
+
+	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);
+
+	return 0;
+}
+
+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,
+};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 06ed0c6..d640e8f 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
 	struct tsens_device *tmdev;
 	const struct of_device_id *id;
 
-	dev = &pdev->dev;
+	if (pdev->dev.of_node)
+		dev = &pdev->dev;
+	else
+		dev = pdev->dev.parent;
+
 	np = dev->of_node;
 
 	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
@@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
 					   &s->slope);
 
 	id = of_match_node(tsens_table, np);
-	if (!id)
-		return -ENODEV;
+	if (id)
+		tmdev->ops = id->data;
+	else
+		tmdev->ops = &ops_8960;
 
-	tmdev->ops = id->data;
 	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
 	    !tmdev->ops->get_temp)
 		return -EINVAL;
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 00183db..10e2e84 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -64,6 +64,6 @@ 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 *);
 
-extern const struct tsens_ops ops_8916, ops_8974;
+extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
 
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

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>
---
 drivers/thermal/qcom/Makefile     |   2 +-
 drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
 drivers/thermal/qcom/tsens.c      |  13 +-
 drivers/thermal/qcom/tsens.h      |   2 +-
 4 files changed, 302 insertions(+), 6 deletions(-)
 create mode 100644 drivers/thermal/qcom/tsens-8960.c

diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index a471100..f3cefd1 100644
--- 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
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
new file mode 100644
index 0000000..00f45e7
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -0,0 +1,291 @@
+/*
+ * 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 "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)
+
+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;
+
+	tmdev->trdy = false;
+
+	return 0;
+}
+
+static int resume_8960(struct tsens_device *tmdev)
+{
+	int ret;
+	unsigned long reg_cntl;
+	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;
+
+	reg_cntl = tmdev->ctx.control;
+	reg_cntl >>= SENSOR0_SHIFT;
+
+	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;
+
+	tmdev->trdy = false;
+	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 = CAL_MDEGC - s->slope * 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)
+{
+	return adc_code * s->slope + s->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];
+
+	if (!tmdev->trdy) {
+		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+		if (ret)
+			return ret;
+		while (!(trdy & TRDY_MASK)) {
+			usleep_range(1000, 1100);
+			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+		}
+		tmdev->trdy = true;
+	}
+
+	ret = regmap_read(tmdev->map, s->status, &code);
+	if (ret)
+		return ret;
+
+	*temp = code_to_mdegC(code, s);
+
+	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);
+
+	return 0;
+}
+
+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,
+};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 06ed0c6..d640e8f 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
 	struct tsens_device *tmdev;
 	const struct of_device_id *id;
 
-	dev = &pdev->dev;
+	if (pdev->dev.of_node)
+		dev = &pdev->dev;
+	else
+		dev = pdev->dev.parent;
+
 	np = dev->of_node;
 
 	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
@@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
 					   &s->slope);
 
 	id = of_match_node(tsens_table, np);
-	if (!id)
-		return -ENODEV;
+	if (id)
+		tmdev->ops = id->data;
+	else
+		tmdev->ops = &ops_8960;
 
-	tmdev->ops = id->data;
 	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
 	    !tmdev->ops->get_temp)
 		return -EINVAL;
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 00183db..10e2e84 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -64,6 +64,6 @@ 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 *);
 
-extern const struct tsens_ops ops_8916, ops_8974;
+extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
 
 #endif /* __QCOM_TSENS_H__ */
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 5/8] arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 105 ++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index ab8e572..cc88412 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -86,6 +86,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 5>;
+
+			trips {
+				cpu_alert0: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 6>;
+
+			trips {
+				cpu_alert1: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 7>;
+
+			trips {
+				cpu_alert2: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 8>;
+
+			trips {
+				cpu_alert3: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 7 0xf04>;
@@ -114,6 +196,29 @@
 			      <0xf9002000 0x1000>;
 		};
 
+		qfprom: qfprom@fc4bc000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qfprom";
+			reg = <0xfc4bc000 0x1000>;
+			tsens_calib: calib@d0 {
+				reg = <0xd0 0x18>;
+			};
+			tsens_backup: backup@440 {
+				reg = <0x440 0x10>;
+			};
+		};
+
+		tsens: thermal-sensor@fc4a8000 {
+			compatible = "qcom,msm8974-tsens";
+			reg = <0xfc4a8000 0x2000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200 3200
+				3200 3200 3200 3200 3200>;
+			#thermal-sensor-cells = <1>;
+		};
+
 		timer@f9020000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 5/8] arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm/boot/dts/qcom-msm8974.dtsi | 105 ++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index ab8e572..cc88412 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -86,6 +86,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 5>;
+
+			trips {
+				cpu_alert0: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 6>;
+
+			trips {
+				cpu_alert1: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 7>;
+
+			trips {
+				cpu_alert2: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 8>;
+
+			trips {
+				cpu_alert3: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 7 0xf04>;
@@ -114,6 +196,29 @@
 			      <0xf9002000 0x1000>;
 		};
 
+		qfprom: qfprom at fc4bc000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qfprom";
+			reg = <0xfc4bc000 0x1000>;
+			tsens_calib: calib at d0 {
+				reg = <0xd0 0x18>;
+			};
+			tsens_backup: backup at 440 {
+				reg = <0x440 0x10>;
+			};
+		};
+
+		tsens: thermal-sensor at fc4a8000 {
+			compatible = "qcom,msm8974-tsens";
+			reg = <0xfc4a8000 0x2000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200 3200
+				3200 3200 3200 3200 3200>;
+			#thermal-sensor-cells = <1>;
+		};
+
 		timer at f9020000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 6/8] arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

TSENS is part of GCC, hence add TSENS properties as part of GCC node.
Also add thermal zones and qfprom nodes.
Update GCC bindings doc to mention the possibility of optional TSENS
properties that can be part of GCC node.

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++++
 arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++++++++++++++++
 2 files changed, 121 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 54c23f3..f1cf499 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -18,6 +18,13 @@ Required properties :
 - #clock-cells : shall contain 1
 - #reset-cells : shall contain 1
 
+Optional properties:
+- Qualcomm TSENS (thermal sensor device) on some devices can
+be part of GCC and hence the TSENS properties can also be
+part of the GCC/clock-controller node.
+For more details on the TSENS properties please refer
+Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+
 Example:
 	clock-controller@900000 {
 		compatible = "qcom,gcc-msm8960";
@@ -25,3 +32,16 @@ Example:
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
+
+Example of GCC with TSENS properties:
+	clock-controller@900000 {
+		compatible = "qcom,gcc-apq8064";
+		reg = <0x00900000 0x4000>;
+		nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+		nvmem-cell-names = "calib", "calib_backup";
+		qcom,tsens-slopes = <1176 1176 1154 1176 1111
+				1132 1132 1199 1132 1199 1132>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+		#thermal-sensor-cells = <1>;
+	};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index d2e94d6..6a0866b 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -75,6 +75,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 7>;
+
+			trips {
+				cpu_alert0: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 8>;
+
+			trips {
+				cpu_alert1: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 9>;
+
+			trips {
+				cpu_alert2: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 10>;
+
+			trips {
+				cpu_alert3: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 10 0x304>;
@@ -364,11 +446,30 @@
 			};
 		};
 
+		qfprom: qfprom@00700000 {
+			compatible	= "qcom,qfprom";
+			reg		= <0x00700000 0x1000>;
+			#address-cells	= <1>;
+			#size-cells	= <1>;
+			ranges;
+			tsens_calib: calib {
+				reg = <0x404 0x10>;
+			};
+			tsens_backup: backup_calib {
+				reg = <0x414 0x10>;
+			};
+		};
+
 		gcc: clock-controller@900000 {
 			compatible = "qcom,gcc-apq8064";
 			reg = <0x00900000 0x4000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <1176 1176 1154 1176 1111
+				1132 1132 1199 1132 1199 1132>;
 			#clock-cells = <1>;
 			#reset-cells = <1>;
+			#thermal-sensor-cells = <1>;
 		};
 
 		lcc: clock-controller@28000000 {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 6/8] arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

TSENS is part of GCC, hence add TSENS properties as part of GCC node.
Also add thermal zones and qfprom nodes.
Update GCC bindings doc to mention the possibility of optional TSENS
properties that can be part of GCC node.

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++++
 arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++++++++++++++++
 2 files changed, 121 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 54c23f3..f1cf499 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -18,6 +18,13 @@ Required properties :
 - #clock-cells : shall contain 1
 - #reset-cells : shall contain 1
 
+Optional properties:
+- Qualcomm TSENS (thermal sensor device) on some devices can
+be part of GCC and hence the TSENS properties can also be
+part of the GCC/clock-controller node.
+For more details on the TSENS properties please refer
+Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+
 Example:
 	clock-controller at 900000 {
 		compatible = "qcom,gcc-msm8960";
@@ -25,3 +32,16 @@ Example:
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
+
+Example of GCC with TSENS properties:
+	clock-controller at 900000 {
+		compatible = "qcom,gcc-apq8064";
+		reg = <0x00900000 0x4000>;
+		nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+		nvmem-cell-names = "calib", "calib_backup";
+		qcom,tsens-slopes = <1176 1176 1154 1176 1111
+				1132 1132 1199 1132 1199 1132>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+		#thermal-sensor-cells = <1>;
+	};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index d2e94d6..6a0866b 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -75,6 +75,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 7>;
+
+			trips {
+				cpu_alert0: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 8>;
+
+			trips {
+				cpu_alert1: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 9>;
+
+			trips {
+				cpu_alert2: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&gcc 10>;
+
+			trips {
+				cpu_alert3: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 10 0x304>;
@@ -364,11 +446,30 @@
 			};
 		};
 
+		qfprom: qfprom at 00700000 {
+			compatible	= "qcom,qfprom";
+			reg		= <0x00700000 0x1000>;
+			#address-cells	= <1>;
+			#size-cells	= <1>;
+			ranges;
+			tsens_calib: calib {
+				reg = <0x404 0x10>;
+			};
+			tsens_backup: backup_calib {
+				reg = <0x414 0x10>;
+			};
+		};
+
 		gcc: clock-controller at 900000 {
 			compatible = "qcom,gcc-apq8064";
 			reg = <0x00900000 0x4000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <1176 1176 1154 1176 1111
+				1132 1132 1199 1132 1199 1132>;
 			#clock-cells = <1>;
 			#reset-cells = <1>;
+			#thermal-sensor-cells = <1>;
 		};
 
 		lcc: clock-controller at 28000000 {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 7/8] arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm/boot/dts/qcom-apq8084.dtsi | 105 ++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index 0554fbd..80570a1 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -75,6 +75,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 5>;
+
+			trips {
+				cpu_alert0: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 6>;
+
+			trips {
+				cpu_alert1: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 7>;
+
+			trips {
+				cpu_alert2: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 8>;
+
+			trips {
+				cpu_alert3: trip@0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip@1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 7 0xf04>;
@@ -103,6 +185,29 @@
 			      <0xf9002000 0x1000>;
 		};
 
+		qfprom: qfprom@fc4bc000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qfprom";
+			reg = <0xfc4bc000 0x1000>;
+			tsens_calib: calib@d0 {
+				reg = <0xd0 0x18>;
+			};
+			tsens_backup: backup@440 {
+				reg = <0x440 0x10>;
+			};
+		};
+
+		tsens: thermal-sensor@fc4a8000 {
+			compatible = "qcom,msm8974-tsens";
+			reg = <0xfc4a8000 0x2000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200 3200
+				3200 3200 3200 3200 3200>;
+			#thermal-sensor-cells = <1>;
+		};
+
 		timer@f9020000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 7/8] arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm/boot/dts/qcom-apq8084.dtsi | 105 ++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index 0554fbd..80570a1 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -75,6 +75,88 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 5>;
+
+			trips {
+				cpu_alert0: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 6>;
+
+			trips {
+				cpu_alert1: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal2 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 7>;
+
+			trips {
+				cpu_alert2: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit2: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal3 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 8>;
+
+			trips {
+				cpu_alert3: trip at 0 {
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit3: trip at 1 {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	cpu-pmu {
 		compatible = "qcom,krait-pmu";
 		interrupts = <1 7 0xf04>;
@@ -103,6 +185,29 @@
 			      <0xf9002000 0x1000>;
 		};
 
+		qfprom: qfprom at fc4bc000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "qcom,qfprom";
+			reg = <0xfc4bc000 0x1000>;
+			tsens_calib: calib at d0 {
+				reg = <0xd0 0x18>;
+			};
+			tsens_backup: backup at 440 {
+				reg = <0x440 0x10>;
+			};
+		};
+
+		tsens: thermal-sensor at fc4a8000 {
+			compatible = "qcom,msm8974-tsens";
+			reg = <0xfc4a8000 0x2000>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200 3200
+				3200 3200 3200 3200 3200>;
+			#thermal-sensor-cells = <1>;
+		};
+
 		timer at f9020000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 8/8] arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-10-09  9:41   ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: edubezval, agross
  Cc: linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang, sboyd,
	srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal,
	Rajendra Nayak

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 3e7083c..63b5262 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -68,6 +68,49 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 4>;
+
+			trips {
+				cpu_alert0: trip@0 {
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip@1 {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 3>;
+
+			trips {
+				cpu_alert1: trip@0 {
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip@1 {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -392,6 +435,29 @@
 			interrupt-controller;
 			#interrupt-cells = <4>;
 		};
+
+		qfprom: qfprom@5c000 {
+			compatible = "qcom,qfprom";
+			reg = <0x5c000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			tsens_caldata: caldata@d0 {
+				reg = <0xd0 0x8>;
+			};
+			tsens_calsel: calsel@ec {
+				reg = <0xec 0x4>;
+			};
+		};
+
+		tsens: thermal-sensor@4a8000 {
+			compatible = "qcom,msm8916-tsens";
+			reg = <0x4a8000 0x2000>;
+			nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+			nvmem-cell-names = "calib", "calib_sel";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
+			qcom,sensor-id = <0 1 2 4 5>;
+			#thermal-sensor-cells = <1>;
+		};
 	};
 };
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH v4 8/8] arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
@ 2015-10-09  9:41   ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-10-09  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Add thermal zones, tsens and qfprom nodes

Cc: Andy Gross <agross@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 3e7083c..63b5262 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -68,6 +68,49 @@
 		};
 	};
 
+	thermal-zones {
+		cpu-thermal0 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 4>;
+
+			trips {
+				cpu_alert0: trip at 0 {
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit0: trip at 1 {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+		cpu-thermal1 {
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+
+			thermal-sensors = <&tsens 3>;
+
+			trips {
+				cpu_alert1: trip at 0 {
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+				cpu_crit1: trip at 1 {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -392,6 +435,29 @@
 			interrupt-controller;
 			#interrupt-cells = <4>;
 		};
+
+		qfprom: qfprom at 5c000 {
+			compatible = "qcom,qfprom";
+			reg = <0x5c000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			tsens_caldata: caldata at d0 {
+				reg = <0xd0 0x8>;
+			};
+			tsens_calsel: calsel at ec {
+				reg = <0xec 0x4>;
+			};
+		};
+
+		tsens: thermal-sensor at 4a8000 {
+			compatible = "qcom,msm8916-tsens";
+			reg = <0x4a8000 0x2000>;
+			nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+			nvmem-cell-names = "calib", "calib_sel";
+			qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
+			qcom,sensor-id = <0 1 2 4 5>;
+			#thermal-sensor-cells = <1>;
+		};
 	};
 };
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 0/8] qcom: Add support for TSENS driver
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-11-02 20:13   ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:13 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

Rajendra,

On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> 
> Eduardo, can you please take a look at the patches and let me
> know if you see any issues.
> 

Thanks for your taking this over. I am assuming this superseeds the
work by Narendran.

Thanks.

> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> (for a dependent patch) to be able to test on ifc6410 board.
> 
> Changes since v3:
> * Dropped 'clk: qcom: create virtual child device for TSENS' which
> is picked up by Stephen
> * Updated GCC bindings with optional TSENS properties
> 
> Changes since v2:
> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> 
> Changes since v1:
> * Created virtual tsens device from gcc driver for 8960,
> with DT having a single node for gcc and tsens
> * Minor fixes with rebasing on 4.3-rc1
> 
> Changes since RFC:
> * Added support for 8916 and 8084
> * Based off the latest nvmem framework patches [1]
> * Minor review fixes for comments mostly from Lina
> 
> This is an attempt to have a single TSENS driver for
> the different versions of the TSENS IP that exist, on
> different qcom msm/apq SoCs'
> Support is added for msm8916, msm8960 and msm8974 families.
> 
> A lot of the work is based of original code from Stephen Boyd
> and Siddartha Mohanadoss. I have also picked some of what
> Narendran Rajan did in his attempt to upstream the support
> for 8960 family. I could not keep the original authorship on
> any of the patches because I ended up moving the code around
> quite a bit in an effort to have a single driver for the
> various devices. I would be glad to change the authorship
> for any of the patches if needed.
> 
> Rajendra Nayak (8):
>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> 
>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 +
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>  16 files changed, 1490 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-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>  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
> 
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-11-02 20:13   ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:13 UTC (permalink / raw)
  To: linux-arm-kernel

Rajendra,

On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> 
> Eduardo, can you please take a look at the patches and let me
> know if you see any issues.
> 

Thanks for your taking this over. I am assuming this superseeds the
work by Narendran.

Thanks.

> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> (for a dependent patch) to be able to test on ifc6410 board.
> 
> Changes since v3:
> * Dropped 'clk: qcom: create virtual child device for TSENS' which
> is picked up by Stephen
> * Updated GCC bindings with optional TSENS properties
> 
> Changes since v2:
> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> 
> Changes since v1:
> * Created virtual tsens device from gcc driver for 8960,
> with DT having a single node for gcc and tsens
> * Minor fixes with rebasing on 4.3-rc1
> 
> Changes since RFC:
> * Added support for 8916 and 8084
> * Based off the latest nvmem framework patches [1]
> * Minor review fixes for comments mostly from Lina
> 
> This is an attempt to have a single TSENS driver for
> the different versions of the TSENS IP that exist, on
> different qcom msm/apq SoCs'
> Support is added for msm8916, msm8960 and msm8974 families.
> 
> A lot of the work is based of original code from Stephen Boyd
> and Siddartha Mohanadoss. I have also picked some of what
> Narendran Rajan did in his attempt to upstream the support
> for 8960 family. I could not keep the original authorship on
> any of the patches because I ended up moving the code around
> quite a bit in an effort to have a single driver for the
> various devices. I would be glad to change the authorship
> for any of the patches if needed.
> 
> Rajendra Nayak (8):
>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> 
>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 +
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>  16 files changed, 1490 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-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>  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
> 
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 0/8] qcom: Add support for TSENS driver
  2015-11-02 20:13   ` Eduardo Valentin
@ 2015-11-02 20:14     ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:14 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

On Mon, Nov 02, 2015 at 12:13:47PM -0800, Eduardo Valentin wrote:
> Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> > Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> > Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> > 
> > Eduardo, can you please take a look at the patches and let me
> > know if you see any issues.
> > 
> 
> Thanks for your taking this over. I am assuming this superseeds the
> work by Narendran.

https://patchwork.kernel.org/patch/5870241/

> 
> Thanks.
> 
> > Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> > (for a dependent patch) to be able to test on ifc6410 board.
> > 
> > Changes since v3:
> > * Dropped 'clk: qcom: create virtual child device for TSENS' which
> > is picked up by Stephen
> > * Updated GCC bindings with optional TSENS properties
> > 
> > Changes since v2:
> > * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> > 
> > Changes since v1:
> > * Created virtual tsens device from gcc driver for 8960,
> > with DT having a single node for gcc and tsens
> > * Minor fixes with rebasing on 4.3-rc1
> > 
> > Changes since RFC:
> > * Added support for 8916 and 8084
> > * Based off the latest nvmem framework patches [1]
> > * Minor review fixes for comments mostly from Lina
> > 
> > This is an attempt to have a single TSENS driver for
> > the different versions of the TSENS IP that exist, on
> > different qcom msm/apq SoCs'
> > Support is added for msm8916, msm8960 and msm8974 families.
> > 
> > A lot of the work is based of original code from Stephen Boyd
> > and Siddartha Mohanadoss. I have also picked some of what
> > Narendran Rajan did in his attempt to upstream the support
> > for 8960 family. I could not keep the original authorship on
> > any of the patches because I ended up moving the code around
> > quite a bit in an effort to have a single driver for the
> > various devices. I would be glad to change the authorship
> > for any of the patches if needed.
> > 
> > Rajendra Nayak (8):
> >   thermal: qcom: tsens: Add a skeletal TSENS drivers
> >   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
> >   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
> >   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
> >   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
> >   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
> >   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
> >   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> > 
> >  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
> >  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
> >  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
> >  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
> >  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
> >  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
> >  drivers/thermal/Kconfig                            |   5 +
> >  drivers/thermal/Makefile                           |   1 +
> >  drivers/thermal/qcom/Kconfig                       |  10 +
> >  drivers/thermal/qcom/Makefile                      |   2 +
> >  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
> >  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
> >  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
> >  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
> >  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
> >  drivers/thermal/qcom/tsens.h                       |  69 +++++
> >  16 files changed, 1490 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-8916.c
> >  create mode 100644 drivers/thermal/qcom/tsens-8960.c
> >  create mode 100644 drivers/thermal/qcom/tsens-8974.c
> >  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
> > 
> > -- 
> > QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> > of Code Aurora Forum, hosted by The Linux Foundation
> > 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-11-02 20:14     ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 02, 2015 at 12:13:47PM -0800, Eduardo Valentin wrote:
> Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> > Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> > Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> > 
> > Eduardo, can you please take a look at the patches and let me
> > know if you see any issues.
> > 
> 
> Thanks for your taking this over. I am assuming this superseeds the
> work by Narendran.

https://patchwork.kernel.org/patch/5870241/

> 
> Thanks.
> 
> > Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> > (for a dependent patch) to be able to test on ifc6410 board.
> > 
> > Changes since v3:
> > * Dropped 'clk: qcom: create virtual child device for TSENS' which
> > is picked up by Stephen
> > * Updated GCC bindings with optional TSENS properties
> > 
> > Changes since v2:
> > * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> > 
> > Changes since v1:
> > * Created virtual tsens device from gcc driver for 8960,
> > with DT having a single node for gcc and tsens
> > * Minor fixes with rebasing on 4.3-rc1
> > 
> > Changes since RFC:
> > * Added support for 8916 and 8084
> > * Based off the latest nvmem framework patches [1]
> > * Minor review fixes for comments mostly from Lina
> > 
> > This is an attempt to have a single TSENS driver for
> > the different versions of the TSENS IP that exist, on
> > different qcom msm/apq SoCs'
> > Support is added for msm8916, msm8960 and msm8974 families.
> > 
> > A lot of the work is based of original code from Stephen Boyd
> > and Siddartha Mohanadoss. I have also picked some of what
> > Narendran Rajan did in his attempt to upstream the support
> > for 8960 family. I could not keep the original authorship on
> > any of the patches because I ended up moving the code around
> > quite a bit in an effort to have a single driver for the
> > various devices. I would be glad to change the authorship
> > for any of the patches if needed.
> > 
> > Rajendra Nayak (8):
> >   thermal: qcom: tsens: Add a skeletal TSENS drivers
> >   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
> >   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
> >   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
> >   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
> >   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
> >   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
> >   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> > 
> >  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
> >  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
> >  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
> >  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
> >  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
> >  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
> >  drivers/thermal/Kconfig                            |   5 +
> >  drivers/thermal/Makefile                           |   1 +
> >  drivers/thermal/qcom/Kconfig                       |  10 +
> >  drivers/thermal/qcom/Makefile                      |   2 +
> >  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
> >  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
> >  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
> >  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
> >  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
> >  drivers/thermal/qcom/tsens.h                       |  69 +++++
> >  16 files changed, 1490 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-8916.c
> >  create mode 100644 drivers/thermal/qcom/tsens-8960.c
> >  create mode 100644 drivers/thermal/qcom/tsens-8974.c
> >  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
> > 
> > -- 
> > QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> > of Code Aurora Forum, hosted by The Linux Foundation
> > 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-10-09  9:41   ` Rajendra Nayak
@ 2015-11-02 20:30     ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:30 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

Hello Rajendra,

On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:

<cut>

> +- #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
> +
> +Optional properties:
> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
> +		  have a fixed number of sensors (like 11) but a given SoC can
> +		  use only 5 of these and they might not always the first 5. They
> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
> +		  describe the subset of the sensors used. If this property is
> +		  missing they are assumed to be the first 'n' sensors numbered
> +		  sequentially in which case the number of sensors defaults to
> +		  the number of slope values.

Can you please elaborate a bit more on why you could not solve this
using the thermal sensor descriptor id?

> +
> +Example:
> +tsens: thermal-sensor@900000 {
> +		compatible = "qcom,msm8916-tsens";
> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
> +		nvmem-cell-names = "caldata", "calsel";
> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;

This property is not documented. Please, also consider my comment on
Narendran's work: use the already existing thermal zone properties.

Have a look on the binding documentation:
Documentation/devicetree/bindings/thermal/thermal.txt

<quote>
Optional property:
- coefficients:         An array of integers (one signed cell) containing
  Type: array           coefficients to compose a linear relation between
  Elem size: one cell   the sensors listed in the thermal-sensors property.
  Elem type: signed     Coefficients defaults to 1, in case this property
                        is not specified. A simple linear polynomial is used:
                        Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn.

                        The coefficients are ordered and they match with sensors
                        by means of sensor ID. Additional coefficients are
                        interpreted as constant offset.
</quote>

Today the code supports only slope + offset linear coefficients. Which I am
assuming you could reuse in your case. 



> +		qcom,sensor-id = <0 1 2 4 5>;
> +		#thermal-sensor-cells = <1>;

How about if you simply make the sensor driver expose all sensors, then in the
thermal zone descriptor, you pick which sensor to use using the thermal sensor
descriptor (quoting the binding again):

ocp {
        ...
        /*
         * A simple IC with several bandgap temperature sensors.
         */
        bandgap0: bandgap@0x0000ED00 {
                ...
                #thermal-sensor-cells = <1>;
        };
};

thermal-zones {
        cpu_thermal: cpu-thermal {
                polling-delay-passive = <250>; /* milliseconds */
                polling-delay = <1000>; /* milliseconds */

                                /* sensor       ID */
                thermal-sensors = <&bandgap0     0>;
	};
	gpu_thermal: gpu-thermal {
                polling-delay-passive = <120>; /* milliseconds */
                polling-delay = <1000>; /* milliseconds */

                                /* sensor       ID */
                thermal-sensors = <&bandgap0     1>;

	};

};

Would that simplify ?

BR,

Eduardo Valentin

> +	};
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 5aabc4b..d49f2bd 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -374,4 +374,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

Please add compile test too.

> +source "drivers/thermal/qcom/Kconfig"
> +endmenu
> +
>  endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..cdaa55f 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>  obj-$(CONFIG_ST_THERMAL)	+= st/
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
> new file mode 100644
> index 0000000..f7e8e40
> --- /dev/null
> +++ b/drivers/thermal/qcom/Kconfig
> @@ -0,0 +1,10 @@
> +config QCOM_TSENS
> +	tristate "Qualcomm TSENS Temperature Alarm"
> +	depends on THERMAL
> +	depends on QCOM_QFPROM

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.
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> new file mode 100644
> index 0000000..401069b
> --- /dev/null
> +++ b/drivers/thermal/qcom/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
> +qcom_tsens-y			+= tsens.o
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> new file mode 100644
> index 0000000..87f5215
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -0,0 +1,199 @@
> +/*
> + * 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 -ENOSYS;
> +}
> +
> +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, ret;
> +	struct thermal_zone_device *tzd;
> +	u32 *hw_id, n = tmdev->num_sensors;
> +	struct device_node *np = tmdev->dev->of_node;
> +
> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
> +	if (!hw_id)
> +		return -ENOMEM;
> +
> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
> +	for (i = 0;  i < tmdev->num_sensors; i++) {
> +		if (ret)
> +			tmdev->sensor[i].hw_id = i;
> +		else
> +			tmdev->sensor[i].hw_id = hw_id[i];
> +		tmdev->sensor[i].tmdev = tmdev;
> +		tmdev->sensor[i].id = i;
> +		tzd = 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, num;
> +	struct device *dev;
> +	struct device_node *np;
> +	struct tsens_sensor *s;
> +	struct tsens_device *tmdev;
> +	const struct of_device_id *id;
> +
> +	dev = &pdev->dev;
> +	np = dev->of_node;
> +
> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> +	if (num <= 0) {
> +		dev_err(dev, "invalid tsens slopes\n");
> +		return -EINVAL;
> +	}
> +
> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
> +			     num * sizeof(*s), GFP_KERNEL);
> +	if (!tmdev)
> +		return -ENOMEM;
> +
> +	tmdev->dev = dev;
> +	tmdev->num_sensors = num;
> +
> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
> +					   &s->slope);
> +
> +	id = of_match_node(tsens_table, np);
> +	if (!id)
> +		return -ENODEV;
> +
> +	tmdev->ops = id->data;
> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
> +	    !tmdev->ops->get_temp)
> +		return -EINVAL;
> +
> +	ret = tmdev->ops->init(tmdev);
> +	if (ret < 0) {
> +		dev_err(dev, "tsens init failed\n");
> +		return ret;
> +	}
> +
> +	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)
> +{
> +	int i;
> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *tzd;
> +
> +	if (tmdev->ops->disable)
> +		tmdev->ops->disable(tmdev);
> +
> +	for (i = 0; i < tmdev->num_sensors; i++) {
> +		tzd = tmdev->sensor[i].tzd;
> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> +	}
> +
> +	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");
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> new file mode 100644
> index 0000000..f0fc353
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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__
> +
> +struct tsens_device;
> +
> +struct tsens_sensor {
> +	struct tsens_device		*tmdev;
> +	struct thermal_zone_device	*tzd;
> +	int				offset;
> +	int				id;
> +	int				hw_id;
> +	u32				slope;
> +	u32				status;
> +};
> +


> +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 *);
> +};

I know this is a set of internal data structures. But, given that you
are creating a driver that supports a family of chips, and that I
assume will be having additions on it in the future, it would
be nice if you add kernel doc entries on these, so people know
what to expect from them.

> +
> +/* 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];
> +};
> +
> +#endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-11-02 20:30     ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Rajendra,

On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:

<cut>

> +- #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
> +
> +Optional properties:
> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
> +		  have a fixed number of sensors (like 11) but a given SoC can
> +		  use only 5 of these and they might not always the first 5. They
> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
> +		  describe the subset of the sensors used. If this property is
> +		  missing they are assumed to be the first 'n' sensors numbered
> +		  sequentially in which case the number of sensors defaults to
> +		  the number of slope values.

Can you please elaborate a bit more on why you could not solve this
using the thermal sensor descriptor id?

> +
> +Example:
> +tsens: thermal-sensor at 900000 {
> +		compatible = "qcom,msm8916-tsens";
> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
> +		nvmem-cell-names = "caldata", "calsel";
> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;

This property is not documented. Please, also consider my comment on
Narendran's work: use the already existing thermal zone properties.

Have a look on the binding documentation:
Documentation/devicetree/bindings/thermal/thermal.txt

<quote>
Optional property:
- coefficients:         An array of integers (one signed cell) containing
  Type: array           coefficients to compose a linear relation between
  Elem size: one cell   the sensors listed in the thermal-sensors property.
  Elem type: signed     Coefficients defaults to 1, in case this property
                        is not specified. A simple linear polynomial is used:
                        Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn.

                        The coefficients are ordered and they match with sensors
                        by means of sensor ID. Additional coefficients are
                        interpreted as constant offset.
</quote>

Today the code supports only slope + offset linear coefficients. Which I am
assuming you could reuse in your case. 



> +		qcom,sensor-id = <0 1 2 4 5>;
> +		#thermal-sensor-cells = <1>;

How about if you simply make the sensor driver expose all sensors, then in the
thermal zone descriptor, you pick which sensor to use using the thermal sensor
descriptor (quoting the binding again):

ocp {
        ...
        /*
         * A simple IC with several bandgap temperature sensors.
         */
        bandgap0: bandgap at 0x0000ED00 {
                ...
                #thermal-sensor-cells = <1>;
        };
};

thermal-zones {
        cpu_thermal: cpu-thermal {
                polling-delay-passive = <250>; /* milliseconds */
                polling-delay = <1000>; /* milliseconds */

                                /* sensor       ID */
                thermal-sensors = <&bandgap0     0>;
	};
	gpu_thermal: gpu-thermal {
                polling-delay-passive = <120>; /* milliseconds */
                polling-delay = <1000>; /* milliseconds */

                                /* sensor       ID */
                thermal-sensors = <&bandgap0     1>;

	};

};

Would that simplify ?

BR,

Eduardo Valentin

> +	};
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 5aabc4b..d49f2bd 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -374,4 +374,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

Please add compile test too.

> +source "drivers/thermal/qcom/Kconfig"
> +endmenu
> +
>  endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..cdaa55f 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>  obj-$(CONFIG_ST_THERMAL)	+= st/
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
> new file mode 100644
> index 0000000..f7e8e40
> --- /dev/null
> +++ b/drivers/thermal/qcom/Kconfig
> @@ -0,0 +1,10 @@
> +config QCOM_TSENS
> +	tristate "Qualcomm TSENS Temperature Alarm"
> +	depends on THERMAL
> +	depends on QCOM_QFPROM

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.
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> new file mode 100644
> index 0000000..401069b
> --- /dev/null
> +++ b/drivers/thermal/qcom/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
> +qcom_tsens-y			+= tsens.o
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> new file mode 100644
> index 0000000..87f5215
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -0,0 +1,199 @@
> +/*
> + * 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 -ENOSYS;
> +}
> +
> +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, ret;
> +	struct thermal_zone_device *tzd;
> +	u32 *hw_id, n = tmdev->num_sensors;
> +	struct device_node *np = tmdev->dev->of_node;
> +
> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
> +	if (!hw_id)
> +		return -ENOMEM;
> +
> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
> +	for (i = 0;  i < tmdev->num_sensors; i++) {
> +		if (ret)
> +			tmdev->sensor[i].hw_id = i;
> +		else
> +			tmdev->sensor[i].hw_id = hw_id[i];
> +		tmdev->sensor[i].tmdev = tmdev;
> +		tmdev->sensor[i].id = i;
> +		tzd = 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, num;
> +	struct device *dev;
> +	struct device_node *np;
> +	struct tsens_sensor *s;
> +	struct tsens_device *tmdev;
> +	const struct of_device_id *id;
> +
> +	dev = &pdev->dev;
> +	np = dev->of_node;
> +
> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> +	if (num <= 0) {
> +		dev_err(dev, "invalid tsens slopes\n");
> +		return -EINVAL;
> +	}
> +
> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
> +			     num * sizeof(*s), GFP_KERNEL);
> +	if (!tmdev)
> +		return -ENOMEM;
> +
> +	tmdev->dev = dev;
> +	tmdev->num_sensors = num;
> +
> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
> +					   &s->slope);
> +
> +	id = of_match_node(tsens_table, np);
> +	if (!id)
> +		return -ENODEV;
> +
> +	tmdev->ops = id->data;
> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
> +	    !tmdev->ops->get_temp)
> +		return -EINVAL;
> +
> +	ret = tmdev->ops->init(tmdev);
> +	if (ret < 0) {
> +		dev_err(dev, "tsens init failed\n");
> +		return ret;
> +	}
> +
> +	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)
> +{
> +	int i;
> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *tzd;
> +
> +	if (tmdev->ops->disable)
> +		tmdev->ops->disable(tmdev);
> +
> +	for (i = 0; i < tmdev->num_sensors; i++) {
> +		tzd = tmdev->sensor[i].tzd;
> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> +	}
> +
> +	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");
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> new file mode 100644
> index 0000000..f0fc353
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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__
> +
> +struct tsens_device;
> +
> +struct tsens_sensor {
> +	struct tsens_device		*tmdev;
> +	struct thermal_zone_device	*tzd;
> +	int				offset;
> +	int				id;
> +	int				hw_id;
> +	u32				slope;
> +	u32				status;
> +};
> +


> +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 *);
> +};

I know this is a set of internal data structures. But, given that you
are creating a driver that supports a family of chips, and that I
assume will be having additions on it in the future, it would
be nice if you add kernel doc entries on these, so people know
what to expect from them.

> +
> +/* 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];
> +};
> +
> +#endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
  2015-10-09  9:41   ` Rajendra Nayak
@ 2015-11-02 20:42     ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:42 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

On Fri, Oct 09, 2015 at 03:11:04PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  drivers/thermal/qcom/Makefile       |   2 +-
>  drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++

Just a small comment on organization, does it make sense to move tsens-common
addition to the first patch, and then leave this patch only with the
support for 8916 (like you did for the other chips)?

>  drivers/thermal/qcom/tsens.c        |   1 +
>  drivers/thermal/qcom/tsens.h        |  11 +++
>  5 files changed, 250 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/thermal/qcom/tsens-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-common.c
> 
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> index 401069b..05c98e4 100644
> --- 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
> +qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
> diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
> new file mode 100644
> index 0000000..a69aea3
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-8916.c
> @@ -0,0 +1,107 @@
> +/*
> + * 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;

Can calibration fail ? In which cases?

> +}
> +
> +const struct tsens_ops ops_8916 = {
> +	.init		= init_common,
> +	.calibrate	= calibrate_8916,
> +	.get_temp	= get_temp_common,
> +};
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> new file mode 100644
> index 0000000..4acf52c
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -0,0 +1,130 @@
> +/*
> + * 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/nvmem-consumer.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of_address.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
> +
> +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);
nip: add a blank line here.
> +	return ret;
> +}
> +
> +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]);
> +
> +		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_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);

Should this function be marked as __init so devm_* works?

> +	if (!tmdev->map)
> +		return -ENODEV;

Should you do iounmap?

> +
> +	return 0;
> +}
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 87f5215..3d49293 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
>  static const struct of_device_id tsens_table[] = {
>  	{
>  		.compatible = "qcom,msm8916-tsens",
> +		.data = &ops_8916,
>  	}, {
>  		.compatible = "qcom,msm8974-tsens",
>  	},
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index f0fc353..0923822 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -13,6 +13,10 @@
>  #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 {
> @@ -55,4 +59,11 @@ struct tsens_device {
>  	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 *);
> +
> +extern const struct tsens_ops ops_8916;
> +
>  #endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
@ 2015-11-02 20:42     ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 09, 2015 at 03:11:04PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  drivers/thermal/qcom/Makefile       |   2 +-
>  drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++

Just a small comment on organization, does it make sense to move tsens-common
addition to the first patch, and then leave this patch only with the
support for 8916 (like you did for the other chips)?

>  drivers/thermal/qcom/tsens.c        |   1 +
>  drivers/thermal/qcom/tsens.h        |  11 +++
>  5 files changed, 250 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/thermal/qcom/tsens-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-common.c
> 
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> index 401069b..05c98e4 100644
> --- 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
> +qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
> diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
> new file mode 100644
> index 0000000..a69aea3
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-8916.c
> @@ -0,0 +1,107 @@
> +/*
> + * 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;

Can calibration fail ? In which cases?

> +}
> +
> +const struct tsens_ops ops_8916 = {
> +	.init		= init_common,
> +	.calibrate	= calibrate_8916,
> +	.get_temp	= get_temp_common,
> +};
> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
> new file mode 100644
> index 0000000..4acf52c
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-common.c
> @@ -0,0 +1,130 @@
> +/*
> + * 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/nvmem-consumer.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/of_address.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
> +
> +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);
nip: add a blank line here.
> +	return ret;
> +}
> +
> +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]);
> +
> +		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_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);

Should this function be marked as __init so devm_* works?

> +	if (!tmdev->map)
> +		return -ENODEV;

Should you do iounmap?

> +
> +	return 0;
> +}
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 87f5215..3d49293 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
>  static const struct of_device_id tsens_table[] = {
>  	{
>  		.compatible = "qcom,msm8916-tsens",
> +		.data = &ops_8916,
>  	}, {
>  		.compatible = "qcom,msm8974-tsens",
>  	},
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index f0fc353..0923822 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -13,6 +13,10 @@
>  #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 {
> @@ -55,4 +59,11 @@ struct tsens_device {
>  	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 *);
> +
> +extern const struct tsens_ops ops_8916;
> +
>  #endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
  2015-10-09  9:41   ` Rajendra Nayak
@ 2015-11-02 20:51     ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:51 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

On Fri, Oct 09, 2015 at 03:11:06PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  drivers/thermal/qcom/Makefile     |   2 +-
>  drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens.c      |  13 +-
>  drivers/thermal/qcom/tsens.h      |   2 +-
>  4 files changed, 302 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
> 
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> index a471100..f3cefd1 100644
> --- 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
> diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
> new file mode 100644
> index 0000000..00f45e7
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-8960.c
> @@ -0,0 +1,291 @@
> +/*
> + * 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 "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)
> +
> +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;
> +
> +	tmdev->trdy = false;
> +
> +	return 0;
> +}
> +
> +static int resume_8960(struct tsens_device *tmdev)
> +{
> +	int ret;
> +	unsigned long reg_cntl;
> +	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;
> +
> +	reg_cntl = tmdev->ctx.control;
> +	reg_cntl >>= SENSOR0_SHIFT;

What the above two lines are doing? are they no-ops?

> +
> +	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;
> +
> +	tmdev->trdy = false;
> +	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);

Oh.. so calibration can fail on prom reads...

> +
> +	for (i = 0; i < num_read; i++, s++)
> +		s->offset = CAL_MDEGC - s->slope * 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)
> +{
> +	return adc_code * s->slope + s->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];
> +
> +	if (!tmdev->trdy) {
> +		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
> +		if (ret)
> +			return ret;
> +		while (!(trdy & TRDY_MASK)) {
> +			usleep_range(1000, 1100);
> +			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
		Is there a maximum amount of tries?

		Would that be any case in which this would be stuck busy
		looping ?
> +		}
> +		tmdev->trdy = true;
> +	}
> +
> +	ret = regmap_read(tmdev->map, s->status, &code);
> +	if (ret)
> +		return ret;
> +
> +	*temp = code_to_mdegC(code, s);
> +
> +	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);

I suppose the thermal tracing could be probably better than a dev_dbg?

> +
> +	return 0;
> +}
> +
> +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,
> +};
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 06ed0c6..d640e8f 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
>  	struct tsens_device *tmdev;
>  	const struct of_device_id *id;
>  
> -	dev = &pdev->dev;
> +	if (pdev->dev.of_node)
> +		dev = &pdev->dev;
> +	else
> +		dev = pdev->dev.parent;
> +

Should this be part of the patch that adds tsens.c?

>  	np = dev->of_node;
>  
>  	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> @@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
>  					   &s->slope);
>  
>  	id = of_match_node(tsens_table, np);
> -	if (!id)
> -		return -ENODEV;
> +	if (id)
> +		tmdev->ops = id->data;
> +	else
> +		tmdev->ops = &ops_8960;
>  
> -	tmdev->ops = id->data;
>  	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>  	    !tmdev->ops->get_temp)
>  		return -EINVAL;
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index 00183db..10e2e84 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -64,6 +64,6 @@ 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 *);
>  
> -extern const struct tsens_ops ops_8916, ops_8974;
> +extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
>  
>  #endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
@ 2015-11-02 20:51     ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 09, 2015 at 03:11:06PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  drivers/thermal/qcom/Makefile     |   2 +-
>  drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
>  drivers/thermal/qcom/tsens.c      |  13 +-
>  drivers/thermal/qcom/tsens.h      |   2 +-
>  4 files changed, 302 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
> 
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> index a471100..f3cefd1 100644
> --- 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
> diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
> new file mode 100644
> index 0000000..00f45e7
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens-8960.c
> @@ -0,0 +1,291 @@
> +/*
> + * 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 "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)
> +
> +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;
> +
> +	tmdev->trdy = false;
> +
> +	return 0;
> +}
> +
> +static int resume_8960(struct tsens_device *tmdev)
> +{
> +	int ret;
> +	unsigned long reg_cntl;
> +	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;
> +
> +	reg_cntl = tmdev->ctx.control;
> +	reg_cntl >>= SENSOR0_SHIFT;

What the above two lines are doing? are they no-ops?

> +
> +	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;
> +
> +	tmdev->trdy = false;
> +	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);

Oh.. so calibration can fail on prom reads...

> +
> +	for (i = 0; i < num_read; i++, s++)
> +		s->offset = CAL_MDEGC - s->slope * 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)
> +{
> +	return adc_code * s->slope + s->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];
> +
> +	if (!tmdev->trdy) {
> +		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
> +		if (ret)
> +			return ret;
> +		while (!(trdy & TRDY_MASK)) {
> +			usleep_range(1000, 1100);
> +			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
		Is there a maximum amount of tries?

		Would that be any case in which this would be stuck busy
		looping ?
> +		}
> +		tmdev->trdy = true;
> +	}
> +
> +	ret = regmap_read(tmdev->map, s->status, &code);
> +	if (ret)
> +		return ret;
> +
> +	*temp = code_to_mdegC(code, s);
> +
> +	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);

I suppose the thermal tracing could be probably better than a dev_dbg?

> +
> +	return 0;
> +}
> +
> +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,
> +};
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> index 06ed0c6..d640e8f 100644
> --- a/drivers/thermal/qcom/tsens.c
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
>  	struct tsens_device *tmdev;
>  	const struct of_device_id *id;
>  
> -	dev = &pdev->dev;
> +	if (pdev->dev.of_node)
> +		dev = &pdev->dev;
> +	else
> +		dev = pdev->dev.parent;
> +

Should this be part of the patch that adds tsens.c?

>  	np = dev->of_node;
>  
>  	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> @@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
>  					   &s->slope);
>  
>  	id = of_match_node(tsens_table, np);
> -	if (!id)
> -		return -ENODEV;
> +	if (id)
> +		tmdev->ops = id->data;
> +	else
> +		tmdev->ops = &ops_8960;
>  
> -	tmdev->ops = id->data;
>  	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>  	    !tmdev->ops->get_temp)
>  		return -EINVAL;
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> index 00183db..10e2e84 100644
> --- a/drivers/thermal/qcom/tsens.h
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -64,6 +64,6 @@ 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 *);
>  
> -extern const struct tsens_ops ops_8916, ops_8974;
> +extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
>  
>  #endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 0/8] qcom: Add support for TSENS driver
  2015-10-09  9:41 ` Rajendra Nayak
@ 2015-11-02 20:54   ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:54 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> 
> Eduardo, can you please take a look at the patches and let me
> know if you see any issues.

I have sent a couple of comments, most of them are not a big deal. But
please, have a look on what concerns the thermal bindings. I want to
reuse what we have as much as possible.

The other point is regarding locking. Given that you have several
sensors, per device, is there any need to have extra locking on top of
what the thermal framework provides? Say, in the case a single device
gets in use in different thermal zones, would the accesses to the
thermal zone attempt to read registers shared by the sensors within
the device?

> 
> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> (for a dependent patch) to be able to test on ifc6410 board.
> 
> Changes since v3:
> * Dropped 'clk: qcom: create virtual child device for TSENS' which
> is picked up by Stephen
> * Updated GCC bindings with optional TSENS properties
> 
> Changes since v2:
> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> 
> Changes since v1:
> * Created virtual tsens device from gcc driver for 8960,
> with DT having a single node for gcc and tsens
> * Minor fixes with rebasing on 4.3-rc1
> 
> Changes since RFC:
> * Added support for 8916 and 8084
> * Based off the latest nvmem framework patches [1]
> * Minor review fixes for comments mostly from Lina
> 
> This is an attempt to have a single TSENS driver for
> the different versions of the TSENS IP that exist, on
> different qcom msm/apq SoCs'
> Support is added for msm8916, msm8960 and msm8974 families.
> 
> A lot of the work is based of original code from Stephen Boyd
> and Siddartha Mohanadoss. I have also picked some of what
> Narendran Rajan did in his attempt to upstream the support
> for 8960 family. I could not keep the original authorship on
> any of the patches because I ended up moving the code around
> quite a bit in an effort to have a single driver for the
> various devices. I would be glad to change the authorship
> for any of the patches if needed.
> 
> Rajendra Nayak (8):
>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> 
>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 +
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>  16 files changed, 1490 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-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>  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
> 
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-11-02 20:54   ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 20:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
> 
> Eduardo, can you please take a look at the patches and let me
> know if you see any issues.

I have sent a couple of comments, most of them are not a big deal. But
please, have a look on what concerns the thermal bindings. I want to
reuse what we have as much as possible.

The other point is regarding locking. Given that you have several
sensors, per device, is there any need to have extra locking on top of
what the thermal framework provides? Say, in the case a single device
gets in use in different thermal zones, would the accesses to the
thermal zone attempt to read registers shared by the sensors within
the device?

> 
> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
> (for a dependent patch) to be able to test on ifc6410 board.
> 
> Changes since v3:
> * Dropped 'clk: qcom: create virtual child device for TSENS' which
> is picked up by Stephen
> * Updated GCC bindings with optional TSENS properties
> 
> Changes since v2:
> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
> 
> Changes since v1:
> * Created virtual tsens device from gcc driver for 8960,
> with DT having a single node for gcc and tsens
> * Minor fixes with rebasing on 4.3-rc1
> 
> Changes since RFC:
> * Added support for 8916 and 8084
> * Based off the latest nvmem framework patches [1]
> * Minor review fixes for comments mostly from Lina
> 
> This is an attempt to have a single TSENS driver for
> the different versions of the TSENS IP that exist, on
> different qcom msm/apq SoCs'
> Support is added for msm8916, msm8960 and msm8974 families.
> 
> A lot of the work is based of original code from Stephen Boyd
> and Siddartha Mohanadoss. I have also picked some of what
> Narendran Rajan did in his attempt to upstream the support
> for 8960 family. I could not keep the original authorship on
> any of the patches because I ended up moving the code around
> quite a bit in an effort to have a single driver for the
> various devices. I would be glad to change the authorship
> for any of the patches if needed.
> 
> Rajendra Nayak (8):
>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
> 
>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 +
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>  16 files changed, 1490 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-8916.c
>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>  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
> 
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-10-09  9:41   ` Rajendra Nayak
@ 2015-11-02 21:09     ` Eduardo Valentin
  -1 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 21:09 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 ++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 ++
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens.c                       | 199 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  58 ++++++
>  7 files changed, 308 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.c
>  create mode 100644 drivers/thermal/qcom/tsens.h
> 
> diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> new file mode 100644
> index 0000000..8b1f26f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> @@ -0,0 +1,33 @@
> +* QCOM SoC Temperature Sensor (TSENS)
> +
> +Required properties:
> +- compatible :
> + - "qcom,msm8916-tsens" : For 8916 Family of SoCs
> + - "qcom,msm8974-tsens" : For 8974 Family of SoCs
> +
> +- reg: Address range of the thermal registers
> +- qcom,tsens-slopes : Must contain slope value for each of the sensors controlled
> +			by this device
> +- #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
> +
> +Optional properties:
> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
> +		  have a fixed number of sensors (like 11) but a given SoC can
> +		  use only 5 of these and they might not always the first 5. They
> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
> +		  describe the subset of the sensors used. If this property is
> +		  missing they are assumed to be the first 'n' sensors numbered
> +		  sequentially in which case the number of sensors defaults to
> +		  the number of slope values.
> +
> +Example:
> +tsens: thermal-sensor@900000 {
> +		compatible = "qcom,msm8916-tsens";
> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
> +		nvmem-cell-names = "caldata", "calsel";
> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
> +		qcom,sensor-id = <0 1 2 4 5>;
> +		#thermal-sensor-cells = <1>;
> +	};
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 5aabc4b..d49f2bd 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -374,4 +374,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
> +source "drivers/thermal/qcom/Kconfig"
> +endmenu
> +
>  endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..cdaa55f 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>  obj-$(CONFIG_ST_THERMAL)	+= st/
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
> new file mode 100644
> index 0000000..f7e8e40
> --- /dev/null
> +++ b/drivers/thermal/qcom/Kconfig
> @@ -0,0 +1,10 @@
> +config QCOM_TSENS
> +	tristate "Qualcomm TSENS Temperature Alarm"
> +	depends on THERMAL
> +	depends on QCOM_QFPROM
> +	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.
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> new file mode 100644
> index 0000000..401069b
> --- /dev/null
> +++ b/drivers/thermal/qcom/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
> +qcom_tsens-y			+= tsens.o
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> new file mode 100644
> index 0000000..87f5215
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -0,0 +1,199 @@
> +/*
> + * 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 -ENOSYS;

Are you sure you meant to say "system call number not supported"?

Maybe ENOTSUPP? Even though it is defined for nfsv3, the error
code is in use all over, and I believe suits better.

> +}
> +
> +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, ret;
> +	struct thermal_zone_device *tzd;
> +	u32 *hw_id, n = tmdev->num_sensors;
> +	struct device_node *np = tmdev->dev->of_node;
> +
> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
> +	if (!hw_id)
> +		return -ENOMEM;
> +
> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
> +	for (i = 0;  i < tmdev->num_sensors; i++) {
> +		if (ret)
> +			tmdev->sensor[i].hw_id = i;
> +		else
> +			tmdev->sensor[i].hw_id = hw_id[i];
> +		tmdev->sensor[i].tmdev = tmdev;
> +		tmdev->sensor[i].id = i;
> +		tzd = 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, num;
> +	struct device *dev;
> +	struct device_node *np;
> +	struct tsens_sensor *s;
> +	struct tsens_device *tmdev;
> +	const struct of_device_id *id;
> +
> +	dev = &pdev->dev;
> +	np = dev->of_node;
> +
> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> +	if (num <= 0) {
> +		dev_err(dev, "invalid tsens slopes\n");
> +		return -EINVAL;
> +	}
> +
> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
> +			     num * sizeof(*s), GFP_KERNEL);
> +	if (!tmdev)
> +		return -ENOMEM;
> +
> +	tmdev->dev = dev;
> +	tmdev->num_sensors = num;
> +
> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
> +					   &s->slope);
> +
> +	id = of_match_node(tsens_table, np);
> +	if (!id)
> +		return -ENODEV;
> +
> +	tmdev->ops = id->data;
> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
> +	    !tmdev->ops->get_temp)
> +		return -EINVAL;
> +
> +	ret = tmdev->ops->init(tmdev);
> +	if (ret < 0) {
> +		dev_err(dev, "tsens init failed\n");
> +		return ret;
> +	}
> +
> +	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)
> +{
> +	int i;
> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *tzd;
> +
> +	if (tmdev->ops->disable)
> +		tmdev->ops->disable(tmdev);
> +
> +	for (i = 0; i < tmdev->num_sensors; i++) {
> +		tzd = tmdev->sensor[i].tzd;
> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> +	}
> +
> +	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");
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> new file mode 100644
> index 0000000..f0fc353
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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__
> +
> +struct tsens_device;
> +
> +struct tsens_sensor {
> +	struct tsens_device		*tmdev;
> +	struct thermal_zone_device	*tzd;
> +	int				offset;
> +	int				id;
> +	int				hw_id;
> +	u32				slope;
> +	u32				status;
> +};
> +
> +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 *);
> +};
> +
> +/* 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];
> +};
> +
> +#endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-11-02 21:09     ` Eduardo Valentin
  0 siblings, 0 replies; 46+ messages in thread
From: Eduardo Valentin @ 2015-11-02 21:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:
> 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>
> ---
>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 ++++
>  drivers/thermal/Kconfig                            |   5 +
>  drivers/thermal/Makefile                           |   1 +
>  drivers/thermal/qcom/Kconfig                       |  10 ++
>  drivers/thermal/qcom/Makefile                      |   2 +
>  drivers/thermal/qcom/tsens.c                       | 199 +++++++++++++++++++++
>  drivers/thermal/qcom/tsens.h                       |  58 ++++++
>  7 files changed, 308 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.c
>  create mode 100644 drivers/thermal/qcom/tsens.h
> 
> diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> new file mode 100644
> index 0000000..8b1f26f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
> @@ -0,0 +1,33 @@
> +* QCOM SoC Temperature Sensor (TSENS)
> +
> +Required properties:
> +- compatible :
> + - "qcom,msm8916-tsens" : For 8916 Family of SoCs
> + - "qcom,msm8974-tsens" : For 8974 Family of SoCs
> +
> +- reg: Address range of the thermal registers
> +- qcom,tsens-slopes : Must contain slope value for each of the sensors controlled
> +			by this device
> +- #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
> +
> +Optional properties:
> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
> +		  have a fixed number of sensors (like 11) but a given SoC can
> +		  use only 5 of these and they might not always the first 5. They
> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
> +		  describe the subset of the sensors used. If this property is
> +		  missing they are assumed to be the first 'n' sensors numbered
> +		  sequentially in which case the number of sensors defaults to
> +		  the number of slope values.
> +
> +Example:
> +tsens: thermal-sensor at 900000 {
> +		compatible = "qcom,msm8916-tsens";
> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
> +		nvmem-cell-names = "caldata", "calsel";
> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
> +		qcom,sensor-id = <0 1 2 4 5>;
> +		#thermal-sensor-cells = <1>;
> +	};
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 5aabc4b..d49f2bd 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -374,4 +374,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
> +source "drivers/thermal/qcom/Kconfig"
> +endmenu
> +
>  endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 26f1608..cdaa55f 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>  obj-$(CONFIG_ST_THERMAL)	+= st/
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
> new file mode 100644
> index 0000000..f7e8e40
> --- /dev/null
> +++ b/drivers/thermal/qcom/Kconfig
> @@ -0,0 +1,10 @@
> +config QCOM_TSENS
> +	tristate "Qualcomm TSENS Temperature Alarm"
> +	depends on THERMAL
> +	depends on QCOM_QFPROM
> +	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.
> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
> new file mode 100644
> index 0000000..401069b
> --- /dev/null
> +++ b/drivers/thermal/qcom/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
> +qcom_tsens-y			+= tsens.o
> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> new file mode 100644
> index 0000000..87f5215
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.c
> @@ -0,0 +1,199 @@
> +/*
> + * 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 -ENOSYS;

Are you sure you meant to say "system call number not supported"?

Maybe ENOTSUPP? Even though it is defined for nfsv3, the error
code is in use all over, and I believe suits better.

> +}
> +
> +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, ret;
> +	struct thermal_zone_device *tzd;
> +	u32 *hw_id, n = tmdev->num_sensors;
> +	struct device_node *np = tmdev->dev->of_node;
> +
> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
> +	if (!hw_id)
> +		return -ENOMEM;
> +
> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
> +	for (i = 0;  i < tmdev->num_sensors; i++) {
> +		if (ret)
> +			tmdev->sensor[i].hw_id = i;
> +		else
> +			tmdev->sensor[i].hw_id = hw_id[i];
> +		tmdev->sensor[i].tmdev = tmdev;
> +		tmdev->sensor[i].id = i;
> +		tzd = 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, num;
> +	struct device *dev;
> +	struct device_node *np;
> +	struct tsens_sensor *s;
> +	struct tsens_device *tmdev;
> +	const struct of_device_id *id;
> +
> +	dev = &pdev->dev;
> +	np = dev->of_node;
> +
> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
> +	if (num <= 0) {
> +		dev_err(dev, "invalid tsens slopes\n");
> +		return -EINVAL;
> +	}
> +
> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
> +			     num * sizeof(*s), GFP_KERNEL);
> +	if (!tmdev)
> +		return -ENOMEM;
> +
> +	tmdev->dev = dev;
> +	tmdev->num_sensors = num;
> +
> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
> +					   &s->slope);
> +
> +	id = of_match_node(tsens_table, np);
> +	if (!id)
> +		return -ENODEV;
> +
> +	tmdev->ops = id->data;
> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
> +	    !tmdev->ops->get_temp)
> +		return -EINVAL;
> +
> +	ret = tmdev->ops->init(tmdev);
> +	if (ret < 0) {
> +		dev_err(dev, "tsens init failed\n");
> +		return ret;
> +	}
> +
> +	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)
> +{
> +	int i;
> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
> +	struct thermal_zone_device *tzd;
> +
> +	if (tmdev->ops->disable)
> +		tmdev->ops->disable(tmdev);
> +
> +	for (i = 0; i < tmdev->num_sensors; i++) {
> +		tzd = tmdev->sensor[i].tzd;
> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
> +	}
> +
> +	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");
> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
> new file mode 100644
> index 0000000..f0fc353
> --- /dev/null
> +++ b/drivers/thermal/qcom/tsens.h
> @@ -0,0 +1,58 @@
> +/*
> + * 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__
> +
> +struct tsens_device;
> +
> +struct tsens_sensor {
> +	struct tsens_device		*tmdev;
> +	struct thermal_zone_device	*tzd;
> +	int				offset;
> +	int				id;
> +	int				hw_id;
> +	u32				slope;
> +	u32				status;
> +};
> +
> +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 *);
> +};
> +
> +/* 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];
> +};
> +
> +#endif /* __QCOM_TSENS_H__ */
> -- 
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> 

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 0/8] qcom: Add support for TSENS driver
  2015-11-02 20:13   ` Eduardo Valentin
@ 2015-11-05  6:51     ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  6:51 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: linux-pm, linux-arm-msm, punit.agrawal, sboyd,
	srinivas.kandagatla, lina.iyer, nrajan, agross, rui.zhang,
	linux-arm-kernel

Hi Eduardo,

On 11/03/2015 01:43 AM, Eduardo Valentin wrote:
> Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
>> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
>> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
>>
>> Eduardo, can you please take a look at the patches and let me
>> know if you see any issues.
>>
> 
> Thanks for your taking this over. I am assuming this superseeds the
> work by Narendran.

Yes, thats correct. I took Naren's work to add support for msm8960
family and created a single driver to work across msm8960 and
msm8974/8916/8084 SoCs.

regards,
Rajendra

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-11-05  6:51     ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  6:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eduardo,

On 11/03/2015 01:43 AM, Eduardo Valentin wrote:
> Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
>> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
>> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
>>
>> Eduardo, can you please take a look at the patches and let me
>> know if you see any issues.
>>
> 
> Thanks for your taking this over. I am assuming this superseeds the
> work by Narendran.

Yes, thats correct. I took Naren's work to add support for msm8960
family and created a single driver to work across msm8960 and
msm8974/8916/8084 SoCs.

regards,
Rajendra

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-11-02 20:30     ` Eduardo Valentin
@ 2015-11-05  6:53       ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  6:53 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: linux-pm, linux-arm-msm, punit.agrawal, sboyd,
	srinivas.kandagatla, lina.iyer, nrajan, agross, rui.zhang,
	linux-arm-kernel


On 11/03/2015 02:00 AM, Eduardo Valentin wrote:
> Hello Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:
> 
> <cut>
> 
>> +- #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
>> +
>> +Optional properties:
>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
>> +		  have a fixed number of sensors (like 11) but a given SoC can
>> +		  use only 5 of these and they might not always the first 5. They
>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>> +		  describe the subset of the sensors used. If this property is
>> +		  missing they are assumed to be the first 'n' sensors numbered
>> +		  sequentially in which case the number of sensors defaults to
>> +		  the number of slope values.
> 
> Can you please elaborate a bit more on why you could not solve this
> using the thermal sensor descriptor id?
> 
>> +
>> +Example:
>> +tsens: thermal-sensor@900000 {
>> +		compatible = "qcom,msm8916-tsens";
>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>> +		nvmem-cell-names = "caldata", "calsel";
>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
> 
> This property is not documented. Please, also consider my comment on
> Narendran's work: use the already existing thermal zone properties.
> 
> Have a look on the binding documentation:
> Documentation/devicetree/bindings/thermal/thermal.txt
> 
> <quote>
> Optional property:
> - coefficients:         An array of integers (one signed cell) containing
>   Type: array           coefficients to compose a linear relation between
>   Elem size: one cell   the sensors listed in the thermal-sensors property.
>   Elem type: signed     Coefficients defaults to 1, in case this property
>                         is not specified. A simple linear polynomial is used:
>                         Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn.
> 
>                         The coefficients are ordered and they match with sensors
>                         by means of sensor ID. Additional coefficients are
>                         interpreted as constant offset.
> </quote>
> 
> Today the code supports only slope + offset linear coefficients. Which I am
> assuming you could reuse in your case.

Sure, I'll take a look at these and see if I can reuse these bindings instead
of creating new ones.

regards,
Rajendra

> 
> 
> 
>> +		qcom,sensor-id = <0 1 2 4 5>;
>> +		#thermal-sensor-cells = <1>;
> 
> How about if you simply make the sensor driver expose all sensors, then in the
> thermal zone descriptor, you pick which sensor to use using the thermal sensor
> descriptor (quoting the binding again):
> 
> ocp {
>         ...
>         /*
>          * A simple IC with several bandgap temperature sensors.
>          */
>         bandgap0: bandgap@0x0000ED00 {
>                 ...
>                 #thermal-sensor-cells = <1>;
>         };
> };
> 
> thermal-zones {
>         cpu_thermal: cpu-thermal {
>                 polling-delay-passive = <250>; /* milliseconds */
>                 polling-delay = <1000>; /* milliseconds */
> 
>                                 /* sensor       ID */
>                 thermal-sensors = <&bandgap0     0>;
> 	};
> 	gpu_thermal: gpu-thermal {
>                 polling-delay-passive = <120>; /* milliseconds */
>                 polling-delay = <1000>; /* milliseconds */
> 
>                                 /* sensor       ID */
>                 thermal-sensors = <&bandgap0     1>;
> 
> 	};
> 
> };
> 
> Would that simplify ?
> 
> BR,
> 
> Eduardo Valentin
> 
>> +	};
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index 5aabc4b..d49f2bd 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -374,4 +374,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
> 
> Please add compile test too.
> 
>> +source "drivers/thermal/qcom/Kconfig"
>> +endmenu
>> +
>>  endif
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index 26f1608..cdaa55f 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>>  obj-$(CONFIG_ST_THERMAL)	+= st/
>> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
>> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
>> new file mode 100644
>> index 0000000..f7e8e40
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/Kconfig
>> @@ -0,0 +1,10 @@
>> +config QCOM_TSENS
>> +	tristate "Qualcomm TSENS Temperature Alarm"
>> +	depends on THERMAL
>> +	depends on QCOM_QFPROM
> 
> 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.
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> new file mode 100644
>> index 0000000..401069b
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/Makefile
>> @@ -0,0 +1,2 @@
>> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
>> +qcom_tsens-y			+= tsens.o
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> new file mode 100644
>> index 0000000..87f5215
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -0,0 +1,199 @@
>> +/*
>> + * 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 -ENOSYS;
>> +}
>> +
>> +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, ret;
>> +	struct thermal_zone_device *tzd;
>> +	u32 *hw_id, n = tmdev->num_sensors;
>> +	struct device_node *np = tmdev->dev->of_node;
>> +
>> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
>> +	if (!hw_id)
>> +		return -ENOMEM;
>> +
>> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
>> +	for (i = 0;  i < tmdev->num_sensors; i++) {
>> +		if (ret)
>> +			tmdev->sensor[i].hw_id = i;
>> +		else
>> +			tmdev->sensor[i].hw_id = hw_id[i];
>> +		tmdev->sensor[i].tmdev = tmdev;
>> +		tmdev->sensor[i].id = i;
>> +		tzd = 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, num;
>> +	struct device *dev;
>> +	struct device_node *np;
>> +	struct tsens_sensor *s;
>> +	struct tsens_device *tmdev;
>> +	const struct of_device_id *id;
>> +
>> +	dev = &pdev->dev;
>> +	np = dev->of_node;
>> +
>> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
>> +	if (num <= 0) {
>> +		dev_err(dev, "invalid tsens slopes\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
>> +			     num * sizeof(*s), GFP_KERNEL);
>> +	if (!tmdev)
>> +		return -ENOMEM;
>> +
>> +	tmdev->dev = dev;
>> +	tmdev->num_sensors = num;
>> +
>> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
>> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
>> +					   &s->slope);
>> +
>> +	id = of_match_node(tsens_table, np);
>> +	if (!id)
>> +		return -ENODEV;
>> +
>> +	tmdev->ops = id->data;
>> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>> +	    !tmdev->ops->get_temp)
>> +		return -EINVAL;
>> +
>> +	ret = tmdev->ops->init(tmdev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "tsens init failed\n");
>> +		return ret;
>> +	}
>> +
>> +	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)
>> +{
>> +	int i;
>> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
>> +	struct thermal_zone_device *tzd;
>> +
>> +	if (tmdev->ops->disable)
>> +		tmdev->ops->disable(tmdev);
>> +
>> +	for (i = 0; i < tmdev->num_sensors; i++) {
>> +		tzd = tmdev->sensor[i].tzd;
>> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
>> +	}
>> +
>> +	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");
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> new file mode 100644
>> index 0000000..f0fc353
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -0,0 +1,58 @@
>> +/*
>> + * 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__
>> +
>> +struct tsens_device;
>> +
>> +struct tsens_sensor {
>> +	struct tsens_device		*tmdev;
>> +	struct thermal_zone_device	*tzd;
>> +	int				offset;
>> +	int				id;
>> +	int				hw_id;
>> +	u32				slope;
>> +	u32				status;
>> +};
>> +
> 
> 
>> +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 *);
>> +};
> 
> I know this is a set of internal data structures. But, given that you
> are creating a driver that supports a family of chips, and that I
> assume will be having additions on it in the future, it would
> be nice if you add kernel doc entries on these, so people know
> what to expect from them.
> 
>> +
>> +/* 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];
>> +};
>> +
>> +#endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-11-05  6:53       ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  6:53 UTC (permalink / raw)
  To: linux-arm-kernel


On 11/03/2015 02:00 AM, Eduardo Valentin wrote:
> Hello Rajendra,
> 
> On Fri, Oct 09, 2015 at 03:11:03PM +0530, Rajendra Nayak wrote:
> 
> <cut>
> 
>> +- #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
>> +
>> +Optional properties:
>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
>> +		  have a fixed number of sensors (like 11) but a given SoC can
>> +		  use only 5 of these and they might not always the first 5. They
>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>> +		  describe the subset of the sensors used. If this property is
>> +		  missing they are assumed to be the first 'n' sensors numbered
>> +		  sequentially in which case the number of sensors defaults to
>> +		  the number of slope values.
> 
> Can you please elaborate a bit more on why you could not solve this
> using the thermal sensor descriptor id?
> 
>> +
>> +Example:
>> +tsens: thermal-sensor at 900000 {
>> +		compatible = "qcom,msm8916-tsens";
>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>> +		nvmem-cell-names = "caldata", "calsel";
>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
> 
> This property is not documented. Please, also consider my comment on
> Narendran's work: use the already existing thermal zone properties.
> 
> Have a look on the binding documentation:
> Documentation/devicetree/bindings/thermal/thermal.txt
> 
> <quote>
> Optional property:
> - coefficients:         An array of integers (one signed cell) containing
>   Type: array           coefficients to compose a linear relation between
>   Elem size: one cell   the sensors listed in the thermal-sensors property.
>   Elem type: signed     Coefficients defaults to 1, in case this property
>                         is not specified. A simple linear polynomial is used:
>                         Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn.
> 
>                         The coefficients are ordered and they match with sensors
>                         by means of sensor ID. Additional coefficients are
>                         interpreted as constant offset.
> </quote>
> 
> Today the code supports only slope + offset linear coefficients. Which I am
> assuming you could reuse in your case.

Sure, I'll take a look at these and see if I can reuse these bindings instead
of creating new ones.

regards,
Rajendra

> 
> 
> 
>> +		qcom,sensor-id = <0 1 2 4 5>;
>> +		#thermal-sensor-cells = <1>;
> 
> How about if you simply make the sensor driver expose all sensors, then in the
> thermal zone descriptor, you pick which sensor to use using the thermal sensor
> descriptor (quoting the binding again):
> 
> ocp {
>         ...
>         /*
>          * A simple IC with several bandgap temperature sensors.
>          */
>         bandgap0: bandgap at 0x0000ED00 {
>                 ...
>                 #thermal-sensor-cells = <1>;
>         };
> };
> 
> thermal-zones {
>         cpu_thermal: cpu-thermal {
>                 polling-delay-passive = <250>; /* milliseconds */
>                 polling-delay = <1000>; /* milliseconds */
> 
>                                 /* sensor       ID */
>                 thermal-sensors = <&bandgap0     0>;
> 	};
> 	gpu_thermal: gpu-thermal {
>                 polling-delay-passive = <120>; /* milliseconds */
>                 polling-delay = <1000>; /* milliseconds */
> 
>                                 /* sensor       ID */
>                 thermal-sensors = <&bandgap0     1>;
> 
> 	};
> 
> };
> 
> Would that simplify ?
> 
> BR,
> 
> Eduardo Valentin
> 
>> +	};
>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
>> index 5aabc4b..d49f2bd 100644
>> --- a/drivers/thermal/Kconfig
>> +++ b/drivers/thermal/Kconfig
>> @@ -374,4 +374,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
> 
> Please add compile test too.
> 
>> +source "drivers/thermal/qcom/Kconfig"
>> +endmenu
>> +
>>  endif
>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>> index 26f1608..cdaa55f 100644
>> --- a/drivers/thermal/Makefile
>> +++ b/drivers/thermal/Makefile
>> @@ -43,5 +43,6 @@ obj-$(CONFIG_TI_SOC_THERMAL)	+= ti-soc-thermal/
>>  obj-$(CONFIG_INT340X_THERMAL)  += int340x_thermal/
>>  obj-$(CONFIG_INTEL_PCH_THERMAL)	+= intel_pch_thermal.o
>>  obj-$(CONFIG_ST_THERMAL)	+= st/
>> +obj-$(CONFIG_QCOM_TSENS)	+= qcom/
>>  obj-$(CONFIG_TEGRA_SOCTHERM)	+= tegra_soctherm.o
>>  obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
>> diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
>> new file mode 100644
>> index 0000000..f7e8e40
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/Kconfig
>> @@ -0,0 +1,10 @@
>> +config QCOM_TSENS
>> +	tristate "Qualcomm TSENS Temperature Alarm"
>> +	depends on THERMAL
>> +	depends on QCOM_QFPROM
> 
> 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.
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> new file mode 100644
>> index 0000000..401069b
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/Makefile
>> @@ -0,0 +1,2 @@
>> +obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
>> +qcom_tsens-y			+= tsens.o
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> new file mode 100644
>> index 0000000..87f5215
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -0,0 +1,199 @@
>> +/*
>> + * 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 -ENOSYS;
>> +}
>> +
>> +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, ret;
>> +	struct thermal_zone_device *tzd;
>> +	u32 *hw_id, n = tmdev->num_sensors;
>> +	struct device_node *np = tmdev->dev->of_node;
>> +
>> +	hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL);
>> +	if (!hw_id)
>> +		return -ENOMEM;
>> +
>> +	ret = of_property_read_u32_array(np, "qcom,sensor-id", hw_id, n);
>> +	for (i = 0;  i < tmdev->num_sensors; i++) {
>> +		if (ret)
>> +			tmdev->sensor[i].hw_id = i;
>> +		else
>> +			tmdev->sensor[i].hw_id = hw_id[i];
>> +		tmdev->sensor[i].tmdev = tmdev;
>> +		tmdev->sensor[i].id = i;
>> +		tzd = 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, num;
>> +	struct device *dev;
>> +	struct device_node *np;
>> +	struct tsens_sensor *s;
>> +	struct tsens_device *tmdev;
>> +	const struct of_device_id *id;
>> +
>> +	dev = &pdev->dev;
>> +	np = dev->of_node;
>> +
>> +	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
>> +	if (num <= 0) {
>> +		dev_err(dev, "invalid tsens slopes\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	tmdev = devm_kzalloc(dev, sizeof(*tmdev) +
>> +			     num * sizeof(*s), GFP_KERNEL);
>> +	if (!tmdev)
>> +		return -ENOMEM;
>> +
>> +	tmdev->dev = dev;
>> +	tmdev->num_sensors = num;
>> +
>> +	for (i = 0, s = tmdev->sensor; i < tmdev->num_sensors; i++, s++)
>> +		of_property_read_u32_index(np, "qcom,tsens-slopes", i,
>> +					   &s->slope);
>> +
>> +	id = of_match_node(tsens_table, np);
>> +	if (!id)
>> +		return -ENODEV;
>> +
>> +	tmdev->ops = id->data;
>> +	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>> +	    !tmdev->ops->get_temp)
>> +		return -EINVAL;
>> +
>> +	ret = tmdev->ops->init(tmdev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "tsens init failed\n");
>> +		return ret;
>> +	}
>> +
>> +	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)
>> +{
>> +	int i;
>> +	struct tsens_device *tmdev = platform_get_drvdata(pdev);
>> +	struct thermal_zone_device *tzd;
>> +
>> +	if (tmdev->ops->disable)
>> +		tmdev->ops->disable(tmdev);
>> +
>> +	for (i = 0; i < tmdev->num_sensors; i++) {
>> +		tzd = tmdev->sensor[i].tzd;
>> +		thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
>> +	}
>> +
>> +	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");
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> new file mode 100644
>> index 0000000..f0fc353
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -0,0 +1,58 @@
>> +/*
>> + * 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__
>> +
>> +struct tsens_device;
>> +
>> +struct tsens_sensor {
>> +	struct tsens_device		*tmdev;
>> +	struct thermal_zone_device	*tzd;
>> +	int				offset;
>> +	int				id;
>> +	int				hw_id;
>> +	u32				slope;
>> +	u32				status;
>> +};
>> +
> 
> 
>> +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 *);
>> +};
> 
> I know this is a set of internal data structures. But, given that you
> are creating a driver that supports a family of chips, and that I
> assume will be having additions on it in the future, it would
> be nice if you add kernel doc entries on these, so people know
> what to expect from them.
> 
>> +
>> +/* 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];
>> +};
>> +
>> +#endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
  2015-11-02 20:42     ` Eduardo Valentin
@ 2015-11-05  7:10       ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  7:10 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: linux-pm, linux-arm-msm, punit.agrawal, sboyd,
	srinivas.kandagatla, lina.iyer, nrajan, agross, rui.zhang,
	linux-arm-kernel


On 11/03/2015 02:12 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:04PM +0530, Rajendra Nayak wrote:
>> 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>
>> ---
>>  drivers/thermal/qcom/Makefile       |   2 +-
>>  drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
>>  drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++
> 
> Just a small comment on organization, does it make sense to move tsens-common
> addition to the first patch, and then leave this patch only with the
> support for 8916 (like you did for the other chips)?

So the common code gets used for 8916 and hence I added it here as part of this patch.
I can as well move it to the first patch in the series, should not be an issue.

> 
>>  drivers/thermal/qcom/tsens.c        |   1 +
>>  drivers/thermal/qcom/tsens.h        |  11 +++
>>  5 files changed, 250 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/thermal/qcom/tsens-8916.c
>>  create mode 100644 drivers/thermal/qcom/tsens-common.c
>>
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> index 401069b..05c98e4 100644
>> --- 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
>> +qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
>> diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
>> new file mode 100644
>> index 0000000..a69aea3
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-8916.c
>> @@ -0,0 +1,107 @@
>> +/*
>> + * 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;
> 
> Can calibration fail ? In which cases?

yes, it can if the eeprom reads fail for instance.

> 
>> +}
>> +
>> +const struct tsens_ops ops_8916 = {
>> +	.init		= init_common,
>> +	.calibrate	= calibrate_8916,
>> +	.get_temp	= get_temp_common,
>> +};
>> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
>> new file mode 100644
>> index 0000000..4acf52c
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-common.c
>> @@ -0,0 +1,130 @@
>> +/*
>> + * 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/nvmem-consumer.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.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
>> +
>> +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);
> nip: add a blank line here.
>> +	return ret;
>> +}
>> +
>> +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]);
>> +
>> +		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_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);
> 
> Should this function be marked as __init so devm_* works?
> 
>> +	if (!tmdev->map)
>> +		return -ENODEV;
> 
> Should you do iounmap?

yes, will fix these.
thanks,
Rajendra

> 
>> +
>> +	return 0;
>> +}
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> index 87f5215..3d49293 100644
>> --- a/drivers/thermal/qcom/tsens.c
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
>>  static const struct of_device_id tsens_table[] = {
>>  	{
>>  		.compatible = "qcom,msm8916-tsens",
>> +		.data = &ops_8916,
>>  	}, {
>>  		.compatible = "qcom,msm8974-tsens",
>>  	},
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> index f0fc353..0923822 100644
>> --- a/drivers/thermal/qcom/tsens.h
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -13,6 +13,10 @@
>>  #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 {
>> @@ -55,4 +59,11 @@ struct tsens_device {
>>  	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 *);
>> +
>> +extern const struct tsens_ops ops_8916;
>> +
>>  #endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
@ 2015-11-05  7:10       ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  7:10 UTC (permalink / raw)
  To: linux-arm-kernel


On 11/03/2015 02:12 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:04PM +0530, Rajendra Nayak wrote:
>> 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>
>> ---
>>  drivers/thermal/qcom/Makefile       |   2 +-
>>  drivers/thermal/qcom/tsens-8916.c   | 107 +++++++++++++++++++++++++++++
>>  drivers/thermal/qcom/tsens-common.c | 130 ++++++++++++++++++++++++++++++++++++
> 
> Just a small comment on organization, does it make sense to move tsens-common
> addition to the first patch, and then leave this patch only with the
> support for 8916 (like you did for the other chips)?

So the common code gets used for 8916 and hence I added it here as part of this patch.
I can as well move it to the first patch in the series, should not be an issue.

> 
>>  drivers/thermal/qcom/tsens.c        |   1 +
>>  drivers/thermal/qcom/tsens.h        |  11 +++
>>  5 files changed, 250 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/thermal/qcom/tsens-8916.c
>>  create mode 100644 drivers/thermal/qcom/tsens-common.c
>>
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> index 401069b..05c98e4 100644
>> --- 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
>> +qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o
>> diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c
>> new file mode 100644
>> index 0000000..a69aea3
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-8916.c
>> @@ -0,0 +1,107 @@
>> +/*
>> + * 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;
> 
> Can calibration fail ? In which cases?

yes, it can if the eeprom reads fail for instance.

> 
>> +}
>> +
>> +const struct tsens_ops ops_8916 = {
>> +	.init		= init_common,
>> +	.calibrate	= calibrate_8916,
>> +	.get_temp	= get_temp_common,
>> +};
>> diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c
>> new file mode 100644
>> index 0000000..4acf52c
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-common.c
>> @@ -0,0 +1,130 @@
>> +/*
>> + * 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/nvmem-consumer.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/of_address.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
>> +
>> +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);
> nip: add a blank line here.
>> +	return ret;
>> +}
>> +
>> +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]);
>> +
>> +		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_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);
> 
> Should this function be marked as __init so devm_* works?
> 
>> +	if (!tmdev->map)
>> +		return -ENODEV;
> 
> Should you do iounmap?

yes, will fix these.
thanks,
Rajendra

> 
>> +
>> +	return 0;
>> +}
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> index 87f5215..3d49293 100644
>> --- a/drivers/thermal/qcom/tsens.c
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -65,6 +65,7 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
>>  static const struct of_device_id tsens_table[] = {
>>  	{
>>  		.compatible = "qcom,msm8916-tsens",
>> +		.data = &ops_8916,
>>  	}, {
>>  		.compatible = "qcom,msm8974-tsens",
>>  	},
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> index f0fc353..0923822 100644
>> --- a/drivers/thermal/qcom/tsens.h
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -13,6 +13,10 @@
>>  #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 {
>> @@ -55,4 +59,11 @@ struct tsens_device {
>>  	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 *);
>> +
>> +extern const struct tsens_ops ops_8916;
>> +
>>  #endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
  2015-11-02 20:51     ` Eduardo Valentin
@ 2015-11-05  8:05       ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  8:05 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal


On 11/03/2015 02:21 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:06PM +0530, Rajendra Nayak wrote:
>> 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>
>> ---
>>  drivers/thermal/qcom/Makefile     |   2 +-
>>  drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
>>  drivers/thermal/qcom/tsens.c      |  13 +-
>>  drivers/thermal/qcom/tsens.h      |   2 +-
>>  4 files changed, 302 insertions(+), 6 deletions(-)
>>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>>
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> index a471100..f3cefd1 100644
>> --- 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
>> diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
>> new file mode 100644
>> index 0000000..00f45e7
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-8960.c
>> @@ -0,0 +1,291 @@
>> +/*
>> + * 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 "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)
>> +
>> +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;
>> +
>> +	tmdev->trdy = false;
>> +
>> +	return 0;
>> +}
>> +
>> +static int resume_8960(struct tsens_device *tmdev)
>> +{
>> +	int ret;
>> +	unsigned long reg_cntl;
>> +	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;
>> +
>> +	reg_cntl = tmdev->ctx.control;
>> +	reg_cntl >>= SENSOR0_SHIFT;
> 
> What the above two lines are doing? are they no-ops?

Looks like some leftover bits which I should have removed.
Will remove it.

> 
>> +
>> +	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;
>> +
>> +	tmdev->trdy = false;
>> +	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);
> 
> Oh.. so calibration can fail on prom reads...
> 
>> +
>> +	for (i = 0; i < num_read; i++, s++)
>> +		s->offset = CAL_MDEGC - s->slope * 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)
>> +{
>> +	return adc_code * s->slope + s->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];
>> +
>> +	if (!tmdev->trdy) {
>> +		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
>> +		if (ret)
>> +			return ret;
>> +		while (!(trdy & TRDY_MASK)) {
>> +			usleep_range(1000, 1100);
>> +			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
> 		Is there a maximum amount of tries?
> 
> 		Would that be any case in which this would be stuck busy
> 		looping ?

right, I'll put some sensible timeout in.

>> +		}
>> +		tmdev->trdy = true;
>> +	}
>> +
>> +	ret = regmap_read(tmdev->map, s->status, &code);
>> +	if (ret)
>> +		return ret;
>> +
>> +	*temp = code_to_mdegC(code, s);
>> +
>> +	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);
> 
> I suppose the thermal tracing could be probably better than a dev_dbg?

Okay, I'll take a look at thermal tracing.

> 
>> +
>> +	return 0;
>> +}
>> +
>> +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,
>> +};
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> index 06ed0c6..d640e8f 100644
>> --- a/drivers/thermal/qcom/tsens.c
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
>>  	struct tsens_device *tmdev;
>>  	const struct of_device_id *id;
>>  
>> -	dev = &pdev->dev;
>> +	if (pdev->dev.of_node)
>> +		dev = &pdev->dev;
>> +	else
>> +		dev = pdev->dev.parent;
>> +
> 
> Should this be part of the patch that adds tsens.c?

This is needed only because tsens is part of gcc in 8960.
So I kept the change here so its easier to co-relate why
its needed.

regards,
Rajendra
> 
>>  	np = dev->of_node;
>>  
>>  	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
>> @@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
>>  					   &s->slope);
>>  
>>  	id = of_match_node(tsens_table, np);
>> -	if (!id)
>> -		return -ENODEV;
>> +	if (id)
>> +		tmdev->ops = id->data;
>> +	else
>> +		tmdev->ops = &ops_8960;
>>  
>> -	tmdev->ops = id->data;
>>  	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>>  	    !tmdev->ops->get_temp)
>>  		return -EINVAL;
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> index 00183db..10e2e84 100644
>> --- a/drivers/thermal/qcom/tsens.h
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -64,6 +64,6 @@ 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 *);
>>  
>> -extern const struct tsens_ops ops_8916, ops_8974;
>> +extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
>>  
>>  #endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
@ 2015-11-05  8:05       ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  8:05 UTC (permalink / raw)
  To: linux-arm-kernel


On 11/03/2015 02:21 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:06PM +0530, Rajendra Nayak wrote:
>> 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>
>> ---
>>  drivers/thermal/qcom/Makefile     |   2 +-
>>  drivers/thermal/qcom/tsens-8960.c | 291 ++++++++++++++++++++++++++++++++++++++
>>  drivers/thermal/qcom/tsens.c      |  13 +-
>>  drivers/thermal/qcom/tsens.h      |   2 +-
>>  4 files changed, 302 insertions(+), 6 deletions(-)
>>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>>
>> diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
>> index a471100..f3cefd1 100644
>> --- 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
>> diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
>> new file mode 100644
>> index 0000000..00f45e7
>> --- /dev/null
>> +++ b/drivers/thermal/qcom/tsens-8960.c
>> @@ -0,0 +1,291 @@
>> +/*
>> + * 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 "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)
>> +
>> +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;
>> +
>> +	tmdev->trdy = false;
>> +
>> +	return 0;
>> +}
>> +
>> +static int resume_8960(struct tsens_device *tmdev)
>> +{
>> +	int ret;
>> +	unsigned long reg_cntl;
>> +	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;
>> +
>> +	reg_cntl = tmdev->ctx.control;
>> +	reg_cntl >>= SENSOR0_SHIFT;
> 
> What the above two lines are doing? are they no-ops?

Looks like some leftover bits which I should have removed.
Will remove it.

> 
>> +
>> +	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;
>> +
>> +	tmdev->trdy = false;
>> +	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);
> 
> Oh.. so calibration can fail on prom reads...
> 
>> +
>> +	for (i = 0; i < num_read; i++, s++)
>> +		s->offset = CAL_MDEGC - s->slope * 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)
>> +{
>> +	return adc_code * s->slope + s->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];
>> +
>> +	if (!tmdev->trdy) {
>> +		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
>> +		if (ret)
>> +			return ret;
>> +		while (!(trdy & TRDY_MASK)) {
>> +			usleep_range(1000, 1100);
>> +			regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
> 		Is there a maximum amount of tries?
> 
> 		Would that be any case in which this would be stuck busy
> 		looping ?

right, I'll put some sensible timeout in.

>> +		}
>> +		tmdev->trdy = true;
>> +	}
>> +
>> +	ret = regmap_read(tmdev->map, s->status, &code);
>> +	if (ret)
>> +		return ret;
>> +
>> +	*temp = code_to_mdegC(code, s);
>> +
>> +	dev_dbg(tmdev->dev, "Sensor%d temp is: %d", id, *temp);
> 
> I suppose the thermal tracing could be probably better than a dev_dbg?

Okay, I'll take a look at thermal tracing.

> 
>> +
>> +	return 0;
>> +}
>> +
>> +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,
>> +};
>> diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
>> index 06ed0c6..d640e8f 100644
>> --- a/drivers/thermal/qcom/tsens.c
>> +++ b/drivers/thermal/qcom/tsens.c
>> @@ -119,7 +119,11 @@ static int tsens_probe(struct platform_device *pdev)
>>  	struct tsens_device *tmdev;
>>  	const struct of_device_id *id;
>>  
>> -	dev = &pdev->dev;
>> +	if (pdev->dev.of_node)
>> +		dev = &pdev->dev;
>> +	else
>> +		dev = pdev->dev.parent;
>> +
> 
> Should this be part of the patch that adds tsens.c?

This is needed only because tsens is part of gcc in 8960.
So I kept the change here so its easier to co-relate why
its needed.

regards,
Rajendra
> 
>>  	np = dev->of_node;
>>  
>>  	num = of_property_count_u32_elems(np, "qcom,tsens-slopes");
>> @@ -141,10 +145,11 @@ static int tsens_probe(struct platform_device *pdev)
>>  					   &s->slope);
>>  
>>  	id = of_match_node(tsens_table, np);
>> -	if (!id)
>> -		return -ENODEV;
>> +	if (id)
>> +		tmdev->ops = id->data;
>> +	else
>> +		tmdev->ops = &ops_8960;
>>  
>> -	tmdev->ops = id->data;
>>  	if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->calibrate ||
>>  	    !tmdev->ops->get_temp)
>>  		return -EINVAL;
>> diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
>> index 00183db..10e2e84 100644
>> --- a/drivers/thermal/qcom/tsens.h
>> +++ b/drivers/thermal/qcom/tsens.h
>> @@ -64,6 +64,6 @@ 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 *);
>>  
>> -extern const struct tsens_ops ops_8916, ops_8974;
>> +extern const struct tsens_ops ops_8960, ops_8916, ops_8974;
>>  
>>  #endif /* __QCOM_TSENS_H__ */
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 0/8] qcom: Add support for TSENS driver
  2015-11-02 20:54   ` Eduardo Valentin
@ 2015-11-05  8:09     ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  8:09 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal



On 11/03/2015 02:24 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
>> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
>> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
>>
>> Eduardo, can you please take a look at the patches and let me
>> know if you see any issues.
> 
> I have sent a couple of comments, most of them are not a big deal. But
> please, have a look on what concerns the thermal bindings. I want to
> reuse what we have as much as possible.

Sure, I'll take a look at the existing bindings.

> 
> The other point is regarding locking. Given that you have several
> sensors, per device, is there any need to have extra locking on top of
> what the thermal framework provides? Say, in the case a single device
> gets in use in different thermal zones, would the accesses to the
> thermal zone attempt to read registers shared by the sensors within
> the device?

I don't see a case where this should happen, but I will check again
to see if there a possibility of ending up with a situation like
this and if it needs additional locking.
Thanks Eduardo for the review.

regards,
Rajendra

> 
>>
>> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
>> (for a dependent patch) to be able to test on ifc6410 board.
>>
>> Changes since v3:
>> * Dropped 'clk: qcom: create virtual child device for TSENS' which
>> is picked up by Stephen
>> * Updated GCC bindings with optional TSENS properties
>>
>> Changes since v2:
>> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
>>
>> Changes since v1:
>> * Created virtual tsens device from gcc driver for 8960,
>> with DT having a single node for gcc and tsens
>> * Minor fixes with rebasing on 4.3-rc1
>>
>> Changes since RFC:
>> * Added support for 8916 and 8084
>> * Based off the latest nvmem framework patches [1]
>> * Minor review fixes for comments mostly from Lina
>>
>> This is an attempt to have a single TSENS driver for
>> the different versions of the TSENS IP that exist, on
>> different qcom msm/apq SoCs'
>> Support is added for msm8916, msm8960 and msm8974 families.
>>
>> A lot of the work is based of original code from Stephen Boyd
>> and Siddartha Mohanadoss. I have also picked some of what
>> Narendran Rajan did in his attempt to upstream the support
>> for 8960 family. I could not keep the original authorship on
>> any of the patches because I ended up moving the code around
>> quite a bit in an effort to have a single driver for the
>> various devices. I would be glad to change the authorship
>> for any of the patches if needed.
>>
>> Rajendra Nayak (8):
>>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
>>
>>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>>  drivers/thermal/Kconfig                            |   5 +
>>  drivers/thermal/Makefile                           |   1 +
>>  drivers/thermal/qcom/Kconfig                       |  10 +
>>  drivers/thermal/qcom/Makefile                      |   2 +
>>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>>  16 files changed, 1490 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-8916.c
>>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>>  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
>>
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 0/8] qcom: Add support for TSENS driver
@ 2015-11-05  8:09     ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-05  8:09 UTC (permalink / raw)
  To: linux-arm-kernel



On 11/03/2015 02:24 AM, Eduardo Valentin wrote:
> On Fri, Oct 09, 2015 at 03:11:02PM +0530, Rajendra Nayak wrote:
>> Patches 1/8 to 4/8 will need to go via the thermal tree/Eduardo.
>> Patches 5/8 to 8/8 will need to go via qcom-msm tree/Andy.
>>
>> Eduardo, can you please take a look at the patches and let me
>> know if you see any issues.
> 
> I have sent a couple of comments, most of them are not a big deal. But
> please, have a look on what concerns the thermal bindings. I want to
> reuse what we have as much as possible.

Sure, I'll take a look at the existing bindings.

> 
> The other point is regarding locking. Given that you have several
> sensors, per device, is there any need to have extra locking on top of
> what the thermal framework provides? Say, in the case a single device
> gets in use in different thermal zones, would the accesses to the
> thermal zone attempt to read registers shared by the sensors within
> the device?

I don't see a case where this should happen, but I will check again
to see if there a possibility of ending up with a situation like
this and if it needs additional locking.
Thanks Eduardo for the review.

regards,
Rajendra

> 
>>
>> Current set of patches apply on 4.3-rc4. Need to pull in clk-next
>> (for a dependent patch) to be able to test on ifc6410 board.
>>
>> Changes since v3:
>> * Dropped 'clk: qcom: create virtual child device for TSENS' which
>> is picked up by Stephen
>> * Updated GCC bindings with optional TSENS properties
>>
>> Changes since v2:
>> * Minor review fixes from Stephen/Punit and rebase on 4.3-rc4
>>
>> Changes since v1:
>> * Created virtual tsens device from gcc driver for 8960,
>> with DT having a single node for gcc and tsens
>> * Minor fixes with rebasing on 4.3-rc1
>>
>> Changes since RFC:
>> * Added support for 8916 and 8084
>> * Based off the latest nvmem framework patches [1]
>> * Minor review fixes for comments mostly from Lina
>>
>> This is an attempt to have a single TSENS driver for
>> the different versions of the TSENS IP that exist, on
>> different qcom msm/apq SoCs'
>> Support is added for msm8916, msm8960 and msm8974 families.
>>
>> A lot of the work is based of original code from Stephen Boyd
>> and Siddartha Mohanadoss. I have also picked some of what
>> Narendran Rajan did in his attempt to upstream the support
>> for 8960 family. I could not keep the original authorship on
>> any of the patches because I ended up moving the code around
>> quite a bit in an effort to have a single driver for the
>> various devices. I would be glad to change the authorship
>> for any of the patches if needed.
>>
>> Rajendra Nayak (8):
>>   thermal: qcom: tsens: Add a skeletal TSENS drivers
>>   thermal: qcom: tsens-8916: Add support for 8916 family of SoCs
>>   thermal: qcom: tsens-8974: Add support for 8974 family of SoCs
>>   thermal: qcom: tsens-8960: Add support for 8960 family of SoCs
>>   arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes
>>   arm: dts: apq8064: Add thermal zones, tsens and qfprom nodes
>>   arm: dts: apq8084: Add thermal zones, tsens and qfprom nodes
>>   arm64: dts: msm8916: Add thermal zones, tsens and qfprom nodes
>>
>>  .../devicetree/bindings/clock/qcom,gcc.txt         |  20 ++
>>  .../devicetree/bindings/thermal/qcom-tsens.txt     |  33 +++
>>  arch/arm/boot/dts/qcom-apq8064.dtsi                | 101 +++++++
>>  arch/arm/boot/dts/qcom-apq8084.dtsi                | 105 ++++++++
>>  arch/arm/boot/dts/qcom-msm8974.dtsi                | 105 ++++++++
>>  arch/arm64/boot/dts/qcom/msm8916.dtsi              |  66 +++++
>>  drivers/thermal/Kconfig                            |   5 +
>>  drivers/thermal/Makefile                           |   1 +
>>  drivers/thermal/qcom/Kconfig                       |  10 +
>>  drivers/thermal/qcom/Makefile                      |   2 +
>>  drivers/thermal/qcom/tsens-8916.c                  | 107 ++++++++
>>  drivers/thermal/qcom/tsens-8960.c                  | 291 +++++++++++++++++++++
>>  drivers/thermal/qcom/tsens-8974.c                  | 239 +++++++++++++++++
>>  drivers/thermal/qcom/tsens-common.c                | 130 +++++++++
>>  drivers/thermal/qcom/tsens.c                       | 206 +++++++++++++++
>>  drivers/thermal/qcom/tsens.h                       |  69 +++++
>>  16 files changed, 1490 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-8916.c
>>  create mode 100644 drivers/thermal/qcom/tsens-8960.c
>>  create mode 100644 drivers/thermal/qcom/tsens-8974.c
>>  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
>>
>> -- 
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-11-05  6:53       ` Rajendra Nayak
@ 2015-11-30  7:09         ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-30  7:09 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: agross, linux-arm-msm, linux-pm, linux-arm-kernel, rui.zhang,
	sboyd, srinivas.kandagatla, nrajan, lina.iyer, punit.agrawal

[]..

>>> +Optional properties:
>>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
>>> +		  have a fixed number of sensors (like 11) but a given SoC can
>>> +		  use only 5 of these and they might not always the first 5. They
>>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>>> +		  describe the subset of the sensors used. If this property is
>>> +		  missing they are assumed to be the first 'n' sensors numbered
>>> +		  sequentially in which case the number of sensors defaults to
>>> +		  the number of slope values.
>>
>> Can you please elaborate a bit more on why you could not solve this
>> using the thermal sensor descriptor id?
>>
>>> +
>>> +Example:
>>> +tsens: thermal-sensor@900000 {
>>> +		compatible = "qcom,msm8916-tsens";
>>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>>> +		nvmem-cell-names = "caldata", "calsel";
>>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
>>


>>> +		qcom,sensor-id = <0 1 2 4 5>;
>>> +		#thermal-sensor-cells = <1>;
>>
>> How about if you simply make the sensor driver expose all sensors, then in the
>> thermal zone descriptor, you pick which sensor to use using the thermal sensor
>> descriptor (quoting the binding again):

Hi Eduardo,

What you suggested would work, except for that the calibration data in eeprom would
be available for only the _subset_ of sensors on the SoC. So the driver in some way would
need to know which exact sensors the eeprom data corresponds to.

If this does not seem like something which needs to be described in DT, I can have the 
data embedded into the driver so it gets picked based on the right compatibles.

regards,
Rajendra

>>
>> ocp {
>>         ...
>>         /*
>>          * A simple IC with several bandgap temperature sensors.
>>          */
>>         bandgap0: bandgap@0x0000ED00 {
>>                 ...
>>                 #thermal-sensor-cells = <1>;
>>         };
>> };
>>
>> thermal-zones {
>>         cpu_thermal: cpu-thermal {
>>                 polling-delay-passive = <250>; /* milliseconds */
>>                 polling-delay = <1000>; /* milliseconds */
>>
>>                                 /* sensor       ID */
>>                 thermal-sensors = <&bandgap0     0>;
>> 	};
>> 	gpu_thermal: gpu-thermal {
>>                 polling-delay-passive = <120>; /* milliseconds */
>>                 polling-delay = <1000>; /* milliseconds */
>>
>>                                 /* sensor       ID */
>>                 thermal-sensors = <&bandgap0     1>;
>>
>> 	};
>>
>> };
>>
>> Would that simplify ?
>>
>> BR,
>>
>> Eduardo Valentin


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-11-30  7:09         ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-11-30  7:09 UTC (permalink / raw)
  To: linux-arm-kernel

[]..

>>> +Optional properties:
>>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A TSENS IP can
>>> +		  have a fixed number of sensors (like 11) but a given SoC can
>>> +		  use only 5 of these and they might not always the first 5. They
>>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>>> +		  describe the subset of the sensors used. If this property is
>>> +		  missing they are assumed to be the first 'n' sensors numbered
>>> +		  sequentially in which case the number of sensors defaults to
>>> +		  the number of slope values.
>>
>> Can you please elaborate a bit more on why you could not solve this
>> using the thermal sensor descriptor id?
>>
>>> +
>>> +Example:
>>> +tsens: thermal-sensor at 900000 {
>>> +		compatible = "qcom,msm8916-tsens";
>>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>>> +		nvmem-cell-names = "caldata", "calsel";
>>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
>>


>>> +		qcom,sensor-id = <0 1 2 4 5>;
>>> +		#thermal-sensor-cells = <1>;
>>
>> How about if you simply make the sensor driver expose all sensors, then in the
>> thermal zone descriptor, you pick which sensor to use using the thermal sensor
>> descriptor (quoting the binding again):

Hi Eduardo,

What you suggested would work, except for that the calibration data in eeprom would
be available for only the _subset_ of sensors on the SoC. So the driver in some way would
need to know which exact sensors the eeprom data corresponds to.

If this does not seem like something which needs to be described in DT, I can have the 
data embedded into the driver so it gets picked based on the right compatibles.

regards,
Rajendra

>>
>> ocp {
>>         ...
>>         /*
>>          * A simple IC with several bandgap temperature sensors.
>>          */
>>         bandgap0: bandgap at 0x0000ED00 {
>>                 ...
>>                 #thermal-sensor-cells = <1>;
>>         };
>> };
>>
>> thermal-zones {
>>         cpu_thermal: cpu-thermal {
>>                 polling-delay-passive = <250>; /* milliseconds */
>>                 polling-delay = <1000>; /* milliseconds */
>>
>>                                 /* sensor       ID */
>>                 thermal-sensors = <&bandgap0     0>;
>> 	};
>> 	gpu_thermal: gpu-thermal {
>>                 polling-delay-passive = <120>; /* milliseconds */
>>                 polling-delay = <1000>; /* milliseconds */
>>
>>                                 /* sensor       ID */
>>                 thermal-sensors = <&bandgap0     1>;
>>
>> 	};
>>
>> };
>>
>> Would that simplify ?
>>
>> BR,
>>
>> Eduardo Valentin


-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
  2015-11-30  7:09         ` Rajendra Nayak
@ 2015-12-10 14:58           ` Rajendra Nayak
  -1 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-12-10 14:58 UTC (permalink / raw)
  To: Rajendra Nayak
  Cc: Eduardo Valentin, agross, linux-arm-msm, linux-pm,
	linux-arm-kernel, rui.zhang, sboyd, srinivas.kandagatla, nrajan,
	lina.iyer, punit.agrawal


> []..
>
>>>> +Optional properties:
>>>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A
>>>> TSENS IP can
>>>> +		  have a fixed number of sensors (like 11) but a given SoC can
>>>> +		  use only 5 of these and they might not always the first 5. They
>>>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>>>> +		  describe the subset of the sensors used. If this property is
>>>> +		  missing they are assumed to be the first 'n' sensors numbered
>>>> +		  sequentially in which case the number of sensors defaults to
>>>> +		  the number of slope values.
>>>
>>> Can you please elaborate a bit more on why you could not solve this
>>> using the thermal sensor descriptor id?
>>>
>>>> +
>>>> +Example:
>>>> +tsens: thermal-sensor@900000 {
>>>> +		compatible = "qcom,msm8916-tsens";
>>>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>>>> +		nvmem-cell-names = "caldata", "calsel";
>>>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
>>>
>
>
>>>> +		qcom,sensor-id = <0 1 2 4 5>;
>>>> +		#thermal-sensor-cells = <1>;
>>>
>>> How about if you simply make the sensor driver expose all sensors, then
>>> in the
>>> thermal zone descriptor, you pick which sensor to use using the thermal
>>> sensor
>>> descriptor (quoting the binding again):
>
> Hi Eduardo,
>
> What you suggested would work, except for that the calibration data in
> eeprom would
> be available for only the _subset_ of sensors on the SoC. So the driver in
> some way would
> need to know which exact sensors the eeprom data corresponds to.
>
> If this does not seem like something which needs to be described in DT, I
> can have the
> data embedded into the driver so it gets picked based on the right
> compatibles.

Hey Eduardo, any thoughts on this?

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers
@ 2015-12-10 14:58           ` Rajendra Nayak
  0 siblings, 0 replies; 46+ messages in thread
From: Rajendra Nayak @ 2015-12-10 14:58 UTC (permalink / raw)
  To: linux-arm-kernel


> []..
>
>>>> +Optional properties:
>>>> +- qcom,sensor-id: List of sensor instances used in a given SoC. A
>>>> TSENS IP can
>>>> +		  have a fixed number of sensors (like 11) but a given SoC can
>>>> +		  use only 5 of these and they might not always the first 5. They
>>>> +		  could be sensors 0, 1, 4, 8 and 9. This property is used to
>>>> +		  describe the subset of the sensors used. If this property is
>>>> +		  missing they are assumed to be the first 'n' sensors numbered
>>>> +		  sequentially in which case the number of sensors defaults to
>>>> +		  the number of slope values.
>>>
>>> Can you please elaborate a bit more on why you could not solve this
>>> using the thermal sensor descriptor id?
>>>
>>>> +
>>>> +Example:
>>>> +tsens: thermal-sensor at 900000 {
>>>> +		compatible = "qcom,msm8916-tsens";
>>>> +		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
>>>> +		nvmem-cell-names = "caldata", "calsel";
>>>> +		qcom,tsens-slopes = <3200 3200 3200 3200 3200>;
>>>
>
>
>>>> +		qcom,sensor-id = <0 1 2 4 5>;
>>>> +		#thermal-sensor-cells = <1>;
>>>
>>> How about if you simply make the sensor driver expose all sensors, then
>>> in the
>>> thermal zone descriptor, you pick which sensor to use using the thermal
>>> sensor
>>> descriptor (quoting the binding again):
>
> Hi Eduardo,
>
> What you suggested would work, except for that the calibration data in
> eeprom would
> be available for only the _subset_ of sensors on the SoC. So the driver in
> some way would
> need to know which exact sensors the eeprom data corresponds to.
>
> If this does not seem like something which needs to be described in DT, I
> can have the
> data embedded into the driver so it gets picked based on the right
> compatibles.

Hey Eduardo, any thoughts on this?

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2015-12-10 14:58 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-09  9:41 [PATCH v4 0/8] qcom: Add support for TSENS driver Rajendra Nayak
2015-10-09  9:41 ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 1/8] thermal: qcom: tsens: Add a skeletal TSENS drivers Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-11-02 20:30   ` Eduardo Valentin
2015-11-02 20:30     ` Eduardo Valentin
2015-11-05  6:53     ` Rajendra Nayak
2015-11-05  6:53       ` Rajendra Nayak
2015-11-30  7:09       ` Rajendra Nayak
2015-11-30  7:09         ` Rajendra Nayak
2015-12-10 14:58         ` Rajendra Nayak
2015-12-10 14:58           ` Rajendra Nayak
2015-11-02 21:09   ` Eduardo Valentin
2015-11-02 21:09     ` Eduardo Valentin
2015-10-09  9:41 ` [PATCH v4 2/8] thermal: qcom: tsens-8916: Add support for 8916 family of SoCs Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-11-02 20:42   ` Eduardo Valentin
2015-11-02 20:42     ` Eduardo Valentin
2015-11-05  7:10     ` Rajendra Nayak
2015-11-05  7:10       ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 3/8] thermal: qcom: tsens-8974: Add support for 8974 " Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 4/8] thermal: qcom: tsens-8960: Add support for 8960 " Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-11-02 20:51   ` Eduardo Valentin
2015-11-02 20:51     ` Eduardo Valentin
2015-11-05  8:05     ` Rajendra Nayak
2015-11-05  8:05       ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 5/8] arm: dts: msm8974: Add thermal zones, tsens and qfprom nodes Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 6/8] arm: dts: apq8064: " Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 7/8] arm: dts: apq8084: " Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-10-09  9:41 ` [PATCH v4 8/8] arm64: dts: msm8916: " Rajendra Nayak
2015-10-09  9:41   ` Rajendra Nayak
2015-11-02 20:13 ` [PATCH v4 0/8] qcom: Add support for TSENS driver Eduardo Valentin
2015-11-02 20:13   ` Eduardo Valentin
2015-11-02 20:14   ` Eduardo Valentin
2015-11-02 20:14     ` Eduardo Valentin
2015-11-05  6:51   ` Rajendra Nayak
2015-11-05  6:51     ` Rajendra Nayak
2015-11-02 20:54 ` Eduardo Valentin
2015-11-02 20:54   ` Eduardo Valentin
2015-11-05  8:09   ` Rajendra Nayak
2015-11-05  8:09     ` Rajendra Nayak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.