diff options
Diffstat (limited to 'target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch')
-rw-r--r-- | target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch b/target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch deleted file mode 100644 index ef7e2f4152..0000000000 --- a/target/linux/ipq806x/patches-4.4/015-1-thermal-qcom-tsens-Add-a-skeletal-TSENS-drivers.patch +++ /dev/null @@ -1,536 +0,0 @@ -From 9066073c6c27994a30187abf3b674770b4088348 Mon Sep 17 00:00:00 2001 -From: Rajendra Nayak <rnayak@codeaurora.org> -Date: Thu, 5 May 2016 14:21:39 +0530 -Subject: thermal: qcom: tsens: Add a skeletal TSENS drivers - -TSENS is Qualcomms' thermal temperature sensor device. It -supports reading temperatures from multiple thermal sensors -present on various QCOM SoCs. -Calibration data is generally read from a non-volatile memory -(eeprom) device. - -Add a skeleton driver with all the necessary abstractions so -a variety of qcom device families which support TSENS can -add driver extensions. - -Also add the required device tree bindings which can be used -to describe the TSENS device in DT. - -Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org> -Reviewed-by: Lina Iyer <lina.iyer@linaro.org> -Signed-off-by: Eduardo Valentin <edubezval@gmail.com> -Signed-off-by: Zhang Rui <rui.zhang@intel.com> ---- - .../devicetree/bindings/thermal/qcom-tsens.txt | 21 +++ - drivers/thermal/Kconfig | 5 + - drivers/thermal/Makefile | 1 + - drivers/thermal/qcom/Kconfig | 11 ++ - drivers/thermal/qcom/Makefile | 2 + - drivers/thermal/qcom/tsens-common.c | 141 +++++++++++++++ - drivers/thermal/qcom/tsens.c | 195 +++++++++++++++++++++ - drivers/thermal/qcom/tsens.h | 90 ++++++++++ - 8 files changed, 466 insertions(+) - create mode 100644 Documentation/devicetree/bindings/thermal/qcom-tsens.txt - create mode 100644 drivers/thermal/qcom/Kconfig - create mode 100644 drivers/thermal/qcom/Makefile - create mode 100644 drivers/thermal/qcom/tsens-common.c - create mode 100644 drivers/thermal/qcom/tsens.c - create mode 100644 drivers/thermal/qcom/tsens.h - ---- /dev/null -+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt -@@ -0,0 +1,21 @@ -+* QCOM SoC Temperature Sensor (TSENS) -+ -+Required properties: -+- compatible : -+ - "qcom,msm8916-tsens" : For 8916 Family of SoCs -+ - "qcom,msm8974-tsens" : For 8974 Family of SoCs -+ - "qcom,msm8996-tsens" : For 8996 Family of SoCs -+ -+- reg: Address range of the thermal registers -+- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. -+- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify -+nvmem cells -+ -+Example: -+tsens: thermal-sensor@900000 { -+ compatible = "qcom,msm8916-tsens"; -+ reg = <0x4a8000 0x2000>; -+ nvmem-cells = <&tsens_caldata>, <&tsens_calsel>; -+ nvmem-cell-names = "caldata", "calsel"; -+ #thermal-sensor-cells = <1>; -+ }; ---- a/drivers/thermal/Kconfig -+++ b/drivers/thermal/Kconfig -@@ -391,4 +391,9 @@ config QCOM_SPMI_TEMP_ALARM - real time die temperature if an ADC is present or an estimate of the - temperature based upon the over temperature stage value. - -+menu "Qualcomm thermal drivers" -+depends on (ARCH_QCOM && OF) || COMPILE_TEST -+source "drivers/thermal/qcom/Kconfig" -+endmenu -+ - endif ---- a/drivers/thermal/Makefile -+++ b/drivers/thermal/Makefile -@@ -48,3 +48,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL) += intel - obj-$(CONFIG_ST_THERMAL) += st/ - obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o - obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o -+obj-$(CONFIG_QCOM_TSENS) += qcom/ ---- /dev/null -+++ b/drivers/thermal/qcom/Kconfig -@@ -0,0 +1,11 @@ -+config QCOM_TSENS -+ tristate "Qualcomm TSENS Temperature Alarm" -+ depends on THERMAL -+ depends on QCOM_QFPROM -+ depends on ARCH_QCOM || COMPILE_TEST -+ help -+ This enables the thermal sysfs driver for the TSENS device. It shows -+ up in Sysfs as a thermal zone with multiple trip points. Disabling the -+ thermal zone device via the mode file results in disabling the sensor. -+ Also able to set threshold temperature for both hot and cold and update -+ when a threshold is reached. ---- /dev/null -+++ b/drivers/thermal/qcom/Makefile -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o -+qcom_tsens-y += tsens.o tsens-common.o ---- /dev/null -+++ b/drivers/thermal/qcom/tsens-common.c -@@ -0,0 +1,141 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/nvmem-consumer.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+#include "tsens.h" -+ -+#define S0_ST_ADDR 0x1030 -+#define SN_ADDR_OFFSET 0x4 -+#define SN_ST_TEMP_MASK 0x3ff -+#define CAL_DEGC_PT1 30 -+#define CAL_DEGC_PT2 120 -+#define SLOPE_FACTOR 1000 -+#define SLOPE_DEFAULT 3200 -+ -+char *qfprom_read(struct device *dev, const char *cname) -+{ -+ struct nvmem_cell *cell; -+ ssize_t data; -+ char *ret; -+ -+ cell = nvmem_cell_get(dev, cname); -+ if (IS_ERR(cell)) -+ return ERR_CAST(cell); -+ -+ ret = nvmem_cell_read(cell, &data); -+ nvmem_cell_put(cell); -+ -+ return ret; -+} -+ -+/* -+ * Use this function on devices where slope and offset calculations -+ * depend on calibration data read from qfprom. On others the slope -+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset -+ * resp. -+ */ -+void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, -+ u32 *p2, u32 mode) -+{ -+ int i; -+ int num, den; -+ -+ for (i = 0; i < tmdev->num_sensors; i++) { -+ dev_dbg(tmdev->dev, -+ "sensor%d - data_point1:%#x data_point2:%#x\n", -+ i, p1[i], p2[i]); -+ -+ tmdev->sensor[i].slope = SLOPE_DEFAULT; -+ if (mode == TWO_PT_CALIB) { -+ /* -+ * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ -+ * temp_120_degc - temp_30_degc (x2 - x1) -+ */ -+ num = p2[i] - p1[i]; -+ num *= SLOPE_FACTOR; -+ den = CAL_DEGC_PT2 - CAL_DEGC_PT1; -+ tmdev->sensor[i].slope = num / den; -+ } -+ -+ tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - -+ (CAL_DEGC_PT1 * -+ tmdev->sensor[i].slope); -+ dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset); -+ } -+} -+ -+static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) -+{ -+ int degc, num, den; -+ -+ num = (adc_code * SLOPE_FACTOR) - s->offset; -+ den = s->slope; -+ -+ if (num > 0) -+ degc = num + (den / 2); -+ else if (num < 0) -+ degc = num - (den / 2); -+ else -+ degc = num; -+ -+ degc /= den; -+ -+ return degc; -+} -+ -+int get_temp_common(struct tsens_device *tmdev, int id, int *temp) -+{ -+ struct tsens_sensor *s = &tmdev->sensor[id]; -+ u32 code; -+ unsigned int sensor_addr; -+ int last_temp = 0, ret; -+ -+ sensor_addr = S0_ST_ADDR + s->hw_id * SN_ADDR_OFFSET; -+ ret = regmap_read(tmdev->map, sensor_addr, &code); -+ if (ret) -+ return ret; -+ last_temp = code & SN_ST_TEMP_MASK; -+ -+ *temp = code_to_degc(last_temp, s) * 1000; -+ -+ return 0; -+} -+ -+static const struct regmap_config tsens_config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+}; -+ -+int __init init_common(struct tsens_device *tmdev) -+{ -+ void __iomem *base; -+ -+ base = of_iomap(tmdev->dev->of_node, 0); -+ if (IS_ERR(base)) -+ return -EINVAL; -+ -+ tmdev->map = devm_regmap_init_mmio(tmdev->dev, base, &tsens_config); -+ if (!tmdev->map) { -+ iounmap(base); -+ return -ENODEV; -+ } -+ -+ return 0; -+} ---- /dev/null -+++ b/drivers/thermal/qcom/tsens.c -@@ -0,0 +1,195 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include <linux/err.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/pm.h> -+#include <linux/slab.h> -+#include <linux/thermal.h> -+#include "tsens.h" -+ -+static int tsens_get_temp(void *data, int *temp) -+{ -+ const struct tsens_sensor *s = data; -+ struct tsens_device *tmdev = s->tmdev; -+ -+ return tmdev->ops->get_temp(tmdev, s->id, temp); -+} -+ -+static int tsens_get_trend(void *data, long *temp) -+{ -+ const struct tsens_sensor *s = data; -+ struct tsens_device *tmdev = s->tmdev; -+ -+ if (tmdev->ops->get_trend) -+ return tmdev->ops->get_trend(tmdev, s->id, temp); -+ -+ return -ENOTSUPP; -+} -+ -+static int tsens_suspend(struct device *dev) -+{ -+ struct tsens_device *tmdev = dev_get_drvdata(dev); -+ -+ if (tmdev->ops && tmdev->ops->suspend) -+ return tmdev->ops->suspend(tmdev); -+ -+ return 0; -+} -+ -+static int tsens_resume(struct device *dev) -+{ -+ struct tsens_device *tmdev = dev_get_drvdata(dev); -+ -+ if (tmdev->ops && tmdev->ops->resume) -+ return tmdev->ops->resume(tmdev); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); -+ -+static const struct of_device_id tsens_table[] = { -+ { -+ .compatible = "qcom,msm8916-tsens", -+ }, { -+ .compatible = "qcom,msm8974-tsens", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, tsens_table); -+ -+static const struct thermal_zone_of_device_ops tsens_of_ops = { -+ .get_temp = tsens_get_temp, -+ .get_trend = tsens_get_trend, -+}; -+ -+static int tsens_register(struct tsens_device *tmdev) -+{ -+ int i; -+ struct thermal_zone_device *tzd; -+ u32 *hw_id, n = tmdev->num_sensors; -+ -+ hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL); -+ if (!hw_id) -+ return -ENOMEM; -+ -+ for (i = 0; i < tmdev->num_sensors; i++) { -+ tmdev->sensor[i].tmdev = tmdev; -+ tmdev->sensor[i].id = i; -+ tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i, -+ &tmdev->sensor[i], -+ &tsens_of_ops); -+ if (IS_ERR(tzd)) -+ continue; -+ tmdev->sensor[i].tzd = tzd; -+ if (tmdev->ops->enable) -+ tmdev->ops->enable(tmdev, i); -+ } -+ return 0; -+} -+ -+static int tsens_probe(struct platform_device *pdev) -+{ -+ int ret, i; -+ struct device *dev; -+ struct device_node *np; -+ struct tsens_sensor *s; -+ struct tsens_device *tmdev; -+ const struct tsens_data *data; -+ const struct of_device_id *id; -+ -+ if (pdev->dev.of_node) -+ dev = &pdev->dev; -+ else -+ dev = pdev->dev.parent; -+ -+ np = dev->of_node; -+ -+ id = of_match_node(tsens_table, np); -+ if (!id) -+ return -EINVAL; -+ -+ data = id->data; -+ -+ if (data->num_sensors <= 0) { -+ dev_err(dev, "invalid number of sensors\n"); -+ return -EINVAL; -+ } -+ -+ tmdev = devm_kzalloc(dev, sizeof(*tmdev) + -+ data->num_sensors * sizeof(*s), GFP_KERNEL); -+ if (!tmdev) -+ return -ENOMEM; -+ -+ tmdev->dev = dev; -+ tmdev->num_sensors = data->num_sensors; -+ tmdev->ops = data->ops; -+ for (i = 0; i < tmdev->num_sensors; i++) { -+ if (data->hw_ids) -+ tmdev->sensor[i].hw_id = data->hw_ids[i]; -+ else -+ tmdev->sensor[i].hw_id = i; -+ } -+ -+ if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp) -+ return -EINVAL; -+ -+ ret = tmdev->ops->init(tmdev); -+ if (ret < 0) { -+ dev_err(dev, "tsens init failed\n"); -+ return ret; -+ } -+ -+ if (tmdev->ops->calibrate) { -+ ret = tmdev->ops->calibrate(tmdev); -+ if (ret < 0) { -+ dev_err(dev, "tsens calibration failed\n"); -+ return ret; -+ } -+ } -+ -+ ret = tsens_register(tmdev); -+ -+ platform_set_drvdata(pdev, tmdev); -+ -+ return ret; -+} -+ -+static int tsens_remove(struct platform_device *pdev) -+{ -+ struct tsens_device *tmdev = platform_get_drvdata(pdev); -+ -+ if (tmdev->ops->disable) -+ tmdev->ops->disable(tmdev); -+ -+ return 0; -+} -+ -+static struct platform_driver tsens_driver = { -+ .probe = tsens_probe, -+ .remove = tsens_remove, -+ .driver = { -+ .name = "qcom-tsens", -+ .pm = &tsens_pm_ops, -+ .of_match_table = tsens_table, -+ }, -+}; -+module_platform_driver(tsens_driver); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("QCOM Temperature Sensor driver"); -+MODULE_ALIAS("platform:qcom-tsens"); ---- /dev/null -+++ b/drivers/thermal/qcom/tsens.h -@@ -0,0 +1,90 @@ -+/* -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#ifndef __QCOM_TSENS_H__ -+#define __QCOM_TSENS_H__ -+ -+#define ONE_PT_CALIB 0x1 -+#define ONE_PT_CALIB2 0x2 -+#define TWO_PT_CALIB 0x3 -+ -+struct tsens_device; -+ -+struct tsens_sensor { -+ struct tsens_device *tmdev; -+ struct thermal_zone_device *tzd; -+ int offset; -+ int id; -+ int hw_id; -+ int slope; -+ u32 status; -+}; -+ -+/** -+ * struct tsens_ops - operations as supported by the tsens device -+ * @init: Function to initialize the tsens device -+ * @calibrate: Function to calibrate the tsens device -+ * @get_temp: Function which returns the temp in millidegC -+ * @enable: Function to enable (clocks/power) tsens device -+ * @disable: Function to disable the tsens device -+ * @suspend: Function to suspend the tsens device -+ * @resume: Function to resume the tsens device -+ * @get_trend: Function to get the thermal/temp trend -+ */ -+struct tsens_ops { -+ /* mandatory callbacks */ -+ int (*init)(struct tsens_device *); -+ int (*calibrate)(struct tsens_device *); -+ int (*get_temp)(struct tsens_device *, int, int *); -+ /* optional callbacks */ -+ int (*enable)(struct tsens_device *, int); -+ void (*disable)(struct tsens_device *); -+ int (*suspend)(struct tsens_device *); -+ int (*resume)(struct tsens_device *); -+ int (*get_trend)(struct tsens_device *, int, long *); -+}; -+ -+/** -+ * struct tsens_data - tsens instance specific data -+ * @num_sensors: Max number of sensors supported by platform -+ * @ops: operations the tsens instance supports -+ * @hw_ids: Subset of sensors ids supported by platform, if not the first n -+ */ -+struct tsens_data { -+ const u32 num_sensors; -+ const struct tsens_ops *ops; -+ unsigned int *hw_ids; -+}; -+ -+/* Registers to be saved/restored across a context loss */ -+struct tsens_context { -+ int threshold; -+ int control; -+}; -+ -+struct tsens_device { -+ struct device *dev; -+ u32 num_sensors; -+ struct regmap *map; -+ struct regmap_field *status_field; -+ struct tsens_context ctx; -+ bool trdy; -+ const struct tsens_ops *ops; -+ struct tsens_sensor sensor[0]; -+}; -+ -+char *qfprom_read(struct device *, const char *); -+void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32); -+int init_common(struct tsens_device *); -+int get_temp_common(struct tsens_device *, int, int *); -+ -+#endif /* __QCOM_TSENS_H__ */ |