thermal: msm8960_tsens: Add APQ8064 support

TSENS is used by the thermal daemon for thermal management.
On APQ8064 there are 11 TSENS sensors that can be used by the
thermal daemon to monitor the temperature across the chip.

TSENS for APQ8064 supports individual slope for each of the
sensors. The offset used in the temperature from each of the
slope is used for temperature calcuation from the ADC code.

Change-Id: I00457aff8d67ab3367882ffe1077af863b90bc49
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
Signed-off-by: David Brown <davidb@codeaurora.org>
This commit is contained in:
Siddartha Mohanadoss
2012-02-07 16:41:38 -08:00
committed by Stephen Boyd
parent ac6e574364
commit 085efea37e
2 changed files with 151 additions and 66 deletions

View File

@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/msm_tsens.h>
#include <linux/io.h>
#include <linux/err.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
@@ -56,10 +57,12 @@ enum tsens_trip_type {
#define SENSOR4_EN BIT(7)
#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \
SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
#define TSENS_MIN_STATUS_MASK BIT(8)
#define TSENS_LOWER_STATUS_CLR BIT(9)
#define TSENS_UPPER_STATUS_CLR BIT(10)
#define TSENS_MAX_STATUS_MASK BIT(11)
#define TSENS_STATUS_CNTL_OFFSET 8
#define TSENS_MIN_STATUS_MASK BIT((tsens_status_cntl_start))
#define TSENS_LOWER_STATUS_CLR BIT((tsens_status_cntl_start + 1))
#define TSENS_UPPER_STATUS_CLR BIT((tsens_status_cntl_start + 2))
#define TSENS_MAX_STATUS_MASK BIT((tsens_status_cntl_start + 3))
#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default */
#define TSENS_8960_SLP_CLK_ENA BIT(26)
@@ -86,6 +89,7 @@ enum tsens_trip_type {
#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
#define TSENS_STATUS_ADDR_OFFSET 2
#define TSENS_SENSOR_STATUS_SIZE 4
#define TSENS_INT_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x0000363c)
#define TSENS_LOWER_INT_MASK BIT(1)
@@ -113,6 +117,26 @@ enum tsens_trip_type {
#define TSENS_8660_CONFIG_MASK (3 << TSENS_8660_CONFIG_SHIFT)
#define TSENS_8660_SLP_CLK_ENA BIT(24)
#define TSENS_8064_SENSOR5_EN BIT(8)
#define TSENS_8064_SENSOR6_EN BIT(9)
#define TSENS_8064_SENSOR7_EN BIT(10)
#define TSENS_8064_SENSOR8_EN BIT(11)
#define TSENS_8064_SENSOR9_EN BIT(12)
#define TSENS_8064_SENSOR10_EN BIT(13)
#define TSENS_8064_SENSORS_EN (SENSORS_EN | \
TSENS_8064_SENSOR5_EN | \
TSENS_8064_SENSOR6_EN | \
TSENS_8064_SENSOR7_EN | \
TSENS_8064_SENSOR8_EN | \
TSENS_8064_SENSOR9_EN | \
TSENS_8064_SENSOR10_EN)
#define TSENS_8064_STATUS_CNTL (MSM_CLK_CTL_BASE + 0x00003660)
#define TSENS_8064_S5_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003664)
#define TSENS_8064_SEQ_SENSORS 5
#define TSENS_8064_S4_S5_OFFSET 40
static int tsens_status_cntl_start;
struct tsens_tm_device_sensor {
struct thermal_zone_device *tz_dev;
enum thermal_device_mode mode;
@@ -121,11 +145,11 @@ struct tsens_tm_device_sensor {
int offset;
int calib_data;
int calib_data_backup;
uint32_t slope_mul_tsens_factor;
};
struct tsens_tm_device {
bool prev_reading_avail;
int slope_mul_tsens_factor;
int tsens_factor;
uint32_t tsens_num_sensor;
enum platform_type hw_type;
@@ -137,26 +161,18 @@ struct tsens_tm_device *tmdev;
/* Temperature on y axis and ADC-code on x-axis */
static int tsens_tz_code_to_degC(int adc_code, int sensor_num)
{
int degC, degcbeforefactor;
degcbeforefactor = adc_code * tmdev->slope_mul_tsens_factor
+ tmdev->sensor[sensor_num].offset;
if (degcbeforefactor == 0)
degC = degcbeforefactor;
else if (degcbeforefactor > 0)
degC = (degcbeforefactor + tmdev->tsens_factor/2)
/ tmdev->tsens_factor;
else /* rounding for negative degrees */
degC = (degcbeforefactor - tmdev->tsens_factor/2)
/ tmdev->tsens_factor;
return degC;
int degc;
degc = (adc_code * tmdev->sensor[sensor_num].slope_mul_tsens_factor
+ tmdev->sensor[sensor_num].offset)
/ tmdev->tsens_factor;
return degc;
}
static int tsens_tz_degC_to_code(int degC, int sensor_num)
{
int code = (degC * tmdev->tsens_factor -
tmdev->sensor[sensor_num].offset
+ tmdev->slope_mul_tsens_factor/2)
/ tmdev->slope_mul_tsens_factor;
tmdev->sensor[sensor_num].offset)
/ tmdev->sensor[sensor_num].slope_mul_tsens_factor;
if (code > TSENS_THRESHOLD_MAX_CODE)
code = TSENS_THRESHOLD_MAX_CODE;
@@ -167,7 +183,7 @@ static int tsens_tz_degC_to_code(int degC, int sensor_num)
static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
{
unsigned int code;
unsigned int code, offset = 0, sensor_addr;
if (!tmdev->prev_reading_avail) {
while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
@@ -176,7 +192,12 @@ static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
TSENS_TRDY_RDY_MAX_TIME);
tmdev->prev_reading_avail = true;
}
code = readl_relaxed(TSENS_S0_STATUS_ADDR +
sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
if (tmdev->hw_type == APQ_8064 &&
sensor_num >= TSENS_8064_SEQ_SENSORS)
offset = TSENS_8064_S4_S5_OFFSET;
code = readl_relaxed(sensor_addr + offset +
(sensor_num << TSENS_STATUS_ADDR_OFFSET));
*temp = tsens_tz_code_to_degC(code, sensor_num);
}
@@ -247,7 +268,8 @@ static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
}
writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
if (tmdev->hw_type == MSM_8960 ||
tmdev->hw_type == MSM_9615)
tmdev->hw_type == MSM_9615 ||
tmdev->hw_type == APQ_8064)
reg |= mask | TSENS_8960_SLP_CLK_ENA
| TSENS_EN;
else
@@ -257,7 +279,11 @@ static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
} else {
reg &= ~mask;
if (!(reg & SENSOR0_EN)) {
if (tmdev->hw_type == MSM_8960 ||
if (tmdev->hw_type == APQ_8064)
reg &= ~(TSENS_8064_SENSORS_EN |
TSENS_8960_SLP_CLK_ENA |
TSENS_EN);
else if (tmdev->hw_type == MSM_8960 ||
tmdev->hw_type == MSM_9615)
reg &= ~(SENSORS_EN |
TSENS_8960_SLP_CLK_ENA |
@@ -319,7 +345,11 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
lo_code = TSENS_THRESHOLD_MIN_CODE;
hi_code = TSENS_THRESHOLD_MAX_CODE;
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
if (tmdev->hw_type == APQ_8064)
reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
else
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
switch (trip) {
case TSENS_TRIP_STAGE3:
@@ -386,14 +416,21 @@ static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
return -EINVAL;
}
if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
else {
if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
if (tmdev->hw_type == APQ_8064)
writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
else
writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
} else {
if (code < lo_code || code > hi_code) {
pr_info("%s with invalid code %x\n", __func__, code);
return -EINVAL;
}
writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
if (tmdev->hw_type == APQ_8064)
writel_relaxed(reg_cntl & ~mask,
TSENS_8064_STATUS_CNTL);
else
writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
}
mb();
return 0;
@@ -465,7 +502,10 @@ static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
lo_code = TSENS_THRESHOLD_MIN_CODE;
hi_code = TSENS_THRESHOLD_MAX_CODE;
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
if (tmdev->hw_type == APQ_8064)
reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
else
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
switch (trip) {
case TSENS_TRIP_STAGE3:
@@ -561,25 +601,40 @@ static irqreturn_t tsens_isr(int irq, void *data)
{
struct tsens_tm_device *tm = data;
unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
unsigned int sensor_addr;
bool upper_th_x, lower_th_x;
int adc_code;
reg = readl_relaxed(TSENS_CNTL_ADDR);
writel_relaxed(reg | TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR,
TSENS_CNTL_ADDR);
if (tmdev->hw_type == APQ_8064) {
reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
} else {
reg = readl_relaxed(TSENS_CNTL_ADDR);
writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
}
mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
>> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
>> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
reg = sensor = readl_relaxed(TSENS_CNTL_ADDR);
sensor &= (uint32_t) SENSORS_EN;
sensor = readl_relaxed(TSENS_CNTL_ADDR);
if (tmdev->hw_type == APQ_8064) {
reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
} else {
reg = sensor;
sensor &= (uint32_t) SENSORS_EN;
}
sensor >>= TSENS_SENSOR0_SHIFT;
sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
if (i == TSENS_8064_SEQ_SENSORS)
sensor_addr += 40;
if (sensor & TSENS_MASK1) {
code = readl_relaxed(TSENS_S0_STATUS_ADDR +
(i << TSENS_STATUS_ADDR_OFFSET));
code = readl_relaxed(sensor_addr);
upper_th_x = code >= threshold;
lower_th_x = code <= threshold_low;
if (upper_th_x)
@@ -589,8 +644,7 @@ static irqreturn_t tsens_isr(int irq, void *data)
if (upper_th_x || lower_th_x) {
/* Notify user space */
schedule_work(&tm->sensor[i].work);
adc_code = readl_relaxed(TSENS_S0_STATUS_ADDR
+ (i << TSENS_STATUS_ADDR_OFFSET));
adc_code = readl_relaxed(sensor_addr);
pr_info("\nTrip point triggered by "
"current temperature (%d degrees) "
"measured by Temperature-Sensor %d\n",
@@ -598,7 +652,11 @@ static irqreturn_t tsens_isr(int irq, void *data)
}
}
sensor >>= 1;
sensor_addr += TSENS_SENSOR_STATUS_SIZE;
}
if (tmdev->hw_type == APQ_8064)
writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
else
writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
mb();
return IRQ_HANDLED;
@@ -609,7 +667,8 @@ static void tsens_disable_mode(void)
unsigned int reg_cntl = 0;
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
tmdev->hw_type == APQ_8064)
writel_relaxed(reg_cntl &
~((((1 << tmdev->tsens_num_sensor) - 1) <<
TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
@@ -624,6 +683,7 @@ static void tsens_disable_mode(void)
static void tsens_hw_init(void)
{
unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
unsigned int reg_status_cntl = 0;
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
@@ -657,6 +717,25 @@ static void tsens_hw_init(void)
(TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
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) |
(((1 << tmdev->tsens_num_sensor) - 1) <<
TSENS_SENSOR0_SHIFT);
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
TSENS_UPPER_STATUS_CLR |
TSENS_MIN_STATUS_MASK |
TSENS_MAX_STATUS_MASK;
writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
reg_cntl |= TSENS_EN;
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
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);
}
reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
@@ -692,8 +771,10 @@ static int tsens_calib_sensors8660(void)
}
tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
TSENS_CAL_DEGC -
tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
tmdev->prev_reading_avail = false;
INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
notify_uspace_tsens_fn);
@@ -703,35 +784,27 @@ static int tsens_calib_sensors8660(void)
static int tsens_calib_sensors8960(void)
{
uint32_t *main_sensor_addr, sensor_shift, *backup_sensor_addr;
uint32_t sensor_mask, i;
uint32_t i;
uint8_t *main_sensor_addr, *backup_sensor_addr;
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
main_sensor_addr = TSENS_8960_QFPROM_ADDR0 +
(TSENS_8960_QFPROM_SHIFT *
((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
sensor_shift = (i % TSENS_8960_QFPROM_SHIFT) * TSENS_RED_SHIFT;
sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 +
(TSENS_8960_QFPROM_SHIFT *
((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
tmdev->sensor[i].calib_data = (readl_relaxed(main_sensor_addr)
& sensor_mask) >> sensor_shift;
tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
tmdev->sensor[i].calib_data_backup =
(readl_relaxed(backup_sensor_addr) &
sensor_mask) >> sensor_shift;
readb_relaxed(backup_sensor_addr);
if (tmdev->sensor[i].calib_data_backup)
tmdev->sensor[i].calib_data =
tmdev->sensor[i].calib_data_backup;
if (!tmdev->sensor[i].calib_data) {
WARN(1, "%s: No temperature sensor:%d data for"
" calibration in QFPROM!\n", __func__, i);
return -ENODEV;
}
tmdev->sensor[i].offset = tmdev->tsens_factor *
TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
tmdev->sensor[i].calib_data;
tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
tmdev->tsens_factor)
- (tmdev->sensor[i].calib_data *
tmdev->sensor[i].slope_mul_tsens_factor);
tmdev->prev_reading_avail = false;
INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
}
@@ -756,7 +829,8 @@ static int tsens_calib_sensors(void)
if (tmdev->hw_type == MSM_8660)
rc = tsens_calib_sensors8660();
else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
tmdev->hw_type == APQ_8064)
rc = tsens_calib_sensors8960();
return rc;
@@ -764,7 +838,7 @@ static int tsens_calib_sensors(void)
int msm_tsens_early_init(struct tsens_platform_data *pdata)
{
int rc = 0;
int rc = 0, i;
if (!pdata) {
pr_err("No TSENS Platform data\n");
@@ -780,7 +854,8 @@ int msm_tsens_early_init(struct tsens_platform_data *pdata)
return -ENOMEM;
}
tmdev->slope_mul_tsens_factor = pdata->slope;
for (i = 0; i < pdata->tsens_num_sensor; i++)
tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
tmdev->tsens_factor = pdata->tsens_factor;
tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
tmdev->hw_type = pdata->hw_type;
@@ -799,9 +874,14 @@ int msm_tsens_early_init(struct tsens_platform_data *pdata)
return rc;
}
if (tmdev->hw_type == APQ_8064)
tsens_status_cntl_start = 0;
else
tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
tsens_hw_init();
pr_info("msm_tsens_early_init: done\n");
pr_debug("msm_tsens_early_init: done\n");
return rc;
}
@@ -809,6 +889,7 @@ int msm_tsens_early_init(struct tsens_platform_data *pdata)
static int __init tsens_tm_init(void)
{
int rc, i;
unsigned int reg_cntl, reg_status;
if (!tmdev) {
pr_info("%s : TSENS early init not done.\n", __func__);
@@ -823,7 +904,7 @@ static int __init tsens_tm_init(void)
tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
TSENS_TRIP_NUM, &tmdev->sensor[i],
&tsens_thermal_zone_ops, 0, 0, 0, 0);
if (tmdev->sensor[i].tz_dev == NULL) {
if (IS_ERR(tmdev->sensor[i].tz_dev)) {
pr_err("%s: thermal_zone_device_register() failed.\n",
__func__);
rc = -ENODEV;
@@ -841,8 +922,11 @@ static int __init tsens_tm_init(void)
goto fail;
}
pr_notice("%s: OK\n", __func__);
reg_status = readl_relaxed(TSENS_8064_STATUS_CNTL);
pr_debug("%s: OK\n", __func__);
mb();
reg_status = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
return 0;
fail:
tsens_disable_mode();

View File

@@ -22,14 +22,15 @@ enum platform_type {
MSM_8660 = 0,
MSM_8960,
MSM_9615,
APQ_8064,
MSM_TYPE
};
struct tsens_platform_data {
int slope;
int tsens_factor;
uint32_t tsens_num_sensor;
enum platform_type hw_type;
int slope[11];
};
struct tsens_device {