thermal: tsens8960: Add suspend/resume for TSENS
TSENS does not operate reliably during VDD_CX minimization.
Incorrect temperature readings are reported on some instances
when Apps processor comes out of suspend. This leads the
TSENS reporting incorrect temperature during system resume.
Change-Id: I882b37fbe290477926c3a242d3092be8b950dfab
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 2d93f78..fbfd191 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1490,6 +1490,11 @@
1132, 1132, 1199, 1132, 1199, 1132},
};
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+};
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init apq8064_map_io(void)
{
@@ -1979,6 +1984,7 @@
&apq_cpudai_slim_4_tx,
&msm8960_gemini_device,
&apq8064_iommu_domain_device,
+ &msm_tsens_device,
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index e249331..dfc973c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1643,6 +1643,11 @@
1142, 1124, 1153, 1175, 1166},
};
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+};
+
#ifdef CONFIG_MSM_FAKE_BATTERY
static struct platform_device fish_battery_device = {
.name = "fish_battery",
@@ -1797,6 +1802,7 @@
&msm_bus_8930_cpss_fpb,
&msm8960_device_cache_erp,
&msm8930_iommu_domain_device,
+ &msm_tsens_device,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index defa33b..dd001bc 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2426,6 +2426,11 @@
.tsens_num_sensor = 5,
};
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+};
+
#ifdef CONFIG_MSM_FAKE_BATTERY
static struct platform_device fish_battery_device = {
.name = "fish_battery",
@@ -2592,6 +2597,7 @@
&msm8960_cache_dump_device,
#endif
&msm8960_iommu_domain_device,
+ &msm_tsens_device,
};
static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index e1adc6c..434df6e 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -659,6 +659,11 @@
.slope = {1176, 1162, 1162, 1149, 1176},
};
+static struct platform_device msm_tsens_device = {
+ .name = "tsens8960-tm",
+ .id = -1,
+};
+
static struct platform_device *common_devices[] = {
&msm9615_device_dmov,
&msm_device_smd,
@@ -725,6 +730,7 @@
&msm_bus_def_fab,
&msm9615_rpm_log_device,
&msm9615_rpm_stat_device,
+ &msm_tsens_device,
};
static void __init msm9615_i2c_init(void)
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 71df297..fbb377e 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -24,6 +24,7 @@
#include <linux/msm_tsens.h>
#include <linux/io.h>
#include <linux/err.h>
+#include <linux/pm.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
@@ -134,6 +135,9 @@
#define TSENS_8064_S5_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003664)
#define TSENS_8064_SEQ_SENSORS 5
#define TSENS_8064_S4_S5_OFFSET 40
+#define TSENS_CNTL_RESUME_MASK 0xfffffff9
+#define TSENS_8960_SENSOR_MASK 0xf8
+#define TSENS_8064_SENSOR_MASK 0x3ff8
static int tsens_status_cntl_start;
@@ -153,6 +157,8 @@
int tsens_factor;
uint32_t tsens_num_sensor;
enum platform_type hw_type;
+ int pm_tsens_thr_data;
+ int pm_tsens_cntl;
struct tsens_tm_device_sensor sensor[0];
};
@@ -265,9 +271,6 @@
return -EINVAL;
if (mode != tm_sensor->mode) {
- pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
- mode);
-
reg = readl_relaxed(TSENS_CNTL_ADDR);
mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
@@ -686,6 +689,83 @@
}
}
+#ifdef CONFIG_PM
+static int tsens_suspend(struct device *dev)
+{
+ int i = 0;
+
+ tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
+ tmdev->pm_tsens_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+ writel_relaxed(tmdev->pm_tsens_cntl &
+ ~(TSENS_8960_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
+ tmdev->prev_reading_avail = 0;
+ for (i = 0; i < tmdev->tsens_num_sensor; i++)
+ tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
+ disable_irq_nosync(TSENS_UPPER_LOWER_INT);
+ mb();
+ return 0;
+}
+
+static int tsens_resume(struct device *dev)
+{
+ unsigned int reg_cntl = 0, reg_cfg = 0, reg_sensor_mask = 0;
+ unsigned int reg_status_cntl = 0, reg_thr_data = 0, i = 0;
+
+ reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+ writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
+
+ if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
+ reg_cntl |= TSENS_8960_SLP_CLK_ENA |
+ (TSENS_MEASURE_PERIOD << 18) |
+ TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
+ SENSORS_EN;
+ writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
+ } else if (tmdev->hw_type == APQ_8064) {
+ reg_cntl |= TSENS_8960_SLP_CLK_ENA |
+ (TSENS_MEASURE_PERIOD << 18) |
+ TSENS_8064_SENSORS_EN;
+ writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
+ reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
+ reg_status_cntl |= TSENS_MIN_STATUS_MASK |
+ TSENS_MAX_STATUS_MASK;
+ writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
+ }
+
+ reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
+ reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
+ (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
+ writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
+
+ writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
+ TSENS_CNTL_ADDR);
+ reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
+ writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
+ reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
+ if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
+ reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
+ >> TSENS_SENSOR0_SHIFT);
+ else {
+ reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
+ >> TSENS_SENSOR0_SHIFT);
+ }
+
+ for (i = 0; i < tmdev->tsens_num_sensor; i++) {
+ if (reg_sensor_mask & TSENS_MASK1)
+ tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
+ reg_sensor_mask >>= 1;
+ }
+
+ enable_irq(TSENS_UPPER_LOWER_INT);
+ mb();
+ return 0;
+}
+
+static const struct dev_pm_ops tsens_pm_ops = {
+ .suspend = tsens_suspend,
+ .resume = tsens_resume,
+};
+#endif
+
static void tsens_disable_mode(void)
{
unsigned int reg_cntl = 0;
@@ -717,8 +797,7 @@
(TSENS_MEASURE_PERIOD << 18) |
TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
- (((1 << tmdev->tsens_num_sensor) - 1) <<
- TSENS_SENSOR0_SHIFT);
+ SENSORS_EN;
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_cntl |= TSENS_EN;
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
@@ -744,8 +823,7 @@
} else if (tmdev->hw_type == APQ_8064) {
reg_cntl |= TSENS_8960_SLP_CLK_ENA |
(TSENS_MEASURE_PERIOD << 18) |
- (((1 << tmdev->tsens_num_sensor) - 1) <<
- TSENS_SENSOR0_SHIFT);
+ TSENS_8064_SENSORS_EN;
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
@@ -910,7 +988,7 @@
return rc;
}
-static int __init tsens_tm_init(void)
+static int __devinit tsens_tm_probe(struct platform_device *pdev)
{
int rc, i;
@@ -958,7 +1036,7 @@
return rc;
}
-static void __exit tsens_tm_remove(void)
+static int __devexit tsens_tm_remove(struct platform_device *pdev)
{
int i;
@@ -969,10 +1047,32 @@
thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
kfree(tmdev);
tmdev = NULL;
+ return 0;
}
-module_init(tsens_tm_init);
-module_exit(tsens_tm_remove);
+static struct platform_driver tsens_tm_driver = {
+ .probe = tsens_tm_probe,
+ .remove = tsens_tm_remove,
+ .driver = {
+ .name = "tsens8960-tm",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &tsens_pm_ops,
+#endif
+ },
+};
+
+static int __init _tsens_tm_init(void)
+{
+ return platform_driver_register(&tsens_tm_driver);
+}
+module_init(_tsens_tm_init);
+
+static void __exit _tsens_tm_remove(void)
+{
+ platform_driver_unregister(&tsens_tm_driver);
+}
+module_exit(_tsens_tm_remove);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h
index f5472ec..1b0d399 100644
--- a/include/linux/msm_tsens.h
+++ b/include/linux/msm_tsens.h
@@ -26,11 +26,13 @@
MSM_TYPE
};
+#define TSENS_MAX_SENSORS 11
+
struct tsens_platform_data {
+ int slope[TSENS_MAX_SENSORS];
int tsens_factor;
uint32_t tsens_num_sensor;
enum platform_type hw_type;
- int slope[11];
};
struct tsens_device {