Commit 62ebb7b1 authored by Zhang Rui's avatar Zhang Rui

Merge branch 'next' of...

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal into eduardo-soc
parents 52addcf9 3c94f17e
* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs
Required properties:
- compatible : "fsl,imx6q-thermal"
- compatible : "fsl,imx6q-tempmon" for i.MX6Q, "fsl,imx6sx-tempmon" for i.MX6SX.
i.MX6SX has two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC,
when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature
is higher than panic threshold, system will auto reboot by SRC module.
- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
control registers, e.g. ANATOP on imx6q.
- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
......
......@@ -23,6 +23,7 @@
*/
#include <linux/thermal.h>
#include <trace/events/thermal.h>
#include "thermal_core.h"
......@@ -34,6 +35,7 @@ static int get_trip_level(struct thermal_zone_device *tz)
{
int count = 0;
unsigned long trip_temp;
enum thermal_trip_type trip_type;
if (tz->trips == 0 || !tz->ops->get_trip_temp)
return 0;
......@@ -43,6 +45,16 @@ static int get_trip_level(struct thermal_zone_device *tz)
if (tz->temperature < trip_temp)
break;
}
/*
* count > 0 only if temperature is greater than first trip
* point, in which case, trip_point = count - 1
*/
if (count > 0) {
tz->ops->get_trip_type(tz, count - 1, &trip_type);
trace_thermal_zone_trip(tz, count - 1, trip_type);
}
return count;
}
......
......@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
......@@ -31,6 +32,11 @@
#define MISC0 0x0150
#define MISC0_REFTOP_SELBIASOFF (1 << 3)
#define MISC1 0x0160
#define MISC1_IRQ_TEMPHIGH (1 << 29)
/* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */
#define MISC1_IRQ_TEMPLOW (1 << 28)
#define MISC1_IRQ_TEMPPANIC (1 << 27)
#define TEMPSENSE0 0x0180
#define TEMPSENSE0_ALARM_VALUE_SHIFT 20
......@@ -43,6 +49,12 @@
#define TEMPSENSE1 0x0190
#define TEMPSENSE1_MEASURE_FREQ 0xffff
/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */
#define TEMPSENSE2 0x0290
#define TEMPSENSE2_LOW_VALUE_SHIFT 0
#define TEMPSENSE2_LOW_VALUE_MASK 0xfff
#define TEMPSENSE2_PANIC_VALUE_SHIFT 16
#define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
#define OCOTP_ANA1 0x04e0
......@@ -66,6 +78,21 @@ enum imx_thermal_trip {
#define FACTOR1 15976
#define FACTOR2 4297157
#define TEMPMON_IMX6Q 1
#define TEMPMON_IMX6SX 2
struct thermal_soc_data {
u32 version;
};
static struct thermal_soc_data thermal_imx6q_data = {
.version = TEMPMON_IMX6Q,
};
static struct thermal_soc_data thermal_imx6sx_data = {
.version = TEMPMON_IMX6SX,
};
struct imx_thermal_data {
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
......@@ -79,8 +106,21 @@ struct imx_thermal_data {
bool irq_enabled;
int irq;
struct clk *thermal_clk;
const struct thermal_soc_data *socdata;
};
static void imx_set_panic_temp(struct imx_thermal_data *data,
signed long panic_temp)
{
struct regmap *map = data->tempmon;
int critical_value;
critical_value = (data->c2 - panic_temp) / data->c1;
regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK);
regmap_write(map, TEMPSENSE2 + REG_SET, critical_value <<
TEMPSENSE2_PANIC_VALUE_SHIFT);
}
static void imx_set_alarm_temp(struct imx_thermal_data *data,
signed long alarm_temp)
{
......@@ -142,13 +182,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
/* See imx_get_sensor_data() for formula derivation */
*temp = data->c2 - n_meas * data->c1;
/* Update alarm value to next higher trip point */
if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
imx_set_alarm_temp(data, data->temp_critical);
if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) {
imx_set_alarm_temp(data, data->temp_passive);
dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
data->alarm_temp / 1000);
/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
if (data->socdata->version == TEMPMON_IMX6Q) {
if (data->alarm_temp == data->temp_passive &&
*temp >= data->temp_passive)
imx_set_alarm_temp(data, data->temp_critical);
if (data->alarm_temp == data->temp_critical &&
*temp < data->temp_passive) {
imx_set_alarm_temp(data, data->temp_passive);
dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
data->alarm_temp / 1000);
}
}
if (*temp != data->last_temp) {
......@@ -398,8 +442,17 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
return IRQ_HANDLED;
}
static const struct of_device_id of_imx_thermal_match[] = {
{ .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
{ .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
static int imx_thermal_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(of_imx_thermal_match, &pdev->dev);
struct imx_thermal_data *data;
struct cpumask clip_cpus;
struct regmap *map;
......@@ -418,6 +471,20 @@ static int imx_thermal_probe(struct platform_device *pdev)
}
data->tempmon = map;
data->socdata = of_id->data;
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
if (data->socdata->version == TEMPMON_IMX6SX) {
regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH |
MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC);
/*
* reset value of LOW ALARM is incorrect, set it to lowest
* value to avoid false trigger of low alarm.
*/
regmap_write(map, TEMPSENSE2 + REG_SET,
TEMPSENSE2_LOW_VALUE_MASK);
}
data->irq = platform_get_irq(pdev, 0);
if (data->irq < 0)
return data->irq;
......@@ -489,6 +556,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
imx_set_alarm_temp(data, data->temp_passive);
if (data->socdata->version == TEMPMON_IMX6SX)
imx_set_panic_temp(data, data->temp_critical);
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
......@@ -550,12 +621,6 @@ static int imx_thermal_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
imx_thermal_suspend, imx_thermal_resume);
static const struct of_device_id of_imx_thermal_match[] = {
{ .compatible = "fsl,imx6q-tempmon", },
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
static struct platform_driver imx_thermal = {
.driver = {
.name = "imx_thermal",
......
......@@ -401,6 +401,10 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
struct of_phandle_args sensor_specs;
int ret, id;
/* Check whether child is enabled or not */
if (!of_device_is_available(child))
continue;
/* For now, thermal framework supports only 1 sensor per zone */
ret = of_parse_phandle_with_args(child, "thermal-sensors",
"#thermal-sensor-cells",
......@@ -771,6 +775,10 @@ int __init of_parse_thermal_zones(void)
struct thermal_zone_device *zone;
struct thermal_zone_params *tzp;
/* Check whether child is enabled or not */
if (!of_device_is_available(child))
continue;
tz = thermal_of_build_thermal_zone(child);
if (IS_ERR(tz)) {
pr_err("failed to build thermal zone %s: %ld\n",
......@@ -838,6 +846,10 @@ void of_thermal_destroy_zones(void)
for_each_child_of_node(np, child) {
struct thermal_zone_device *zone;
/* Check whether child is enabled or not */
if (!of_device_is_available(child))
continue;
zone = thermal_zone_get_zone_by_name(child->name);
if (IS_ERR(zone))
continue;
......
......@@ -23,6 +23,7 @@
*/
#include <linux/thermal.h>
#include <trace/events/thermal.h>
#include "thermal_core.h"
......@@ -129,8 +130,10 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
trend = get_tz_trend(tz, trip);
if (tz->temperature >= trip_temp)
if (tz->temperature >= trip_temp) {
throttle = true;
trace_thermal_zone_trip(tz, trip, trip_type);
}
dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n",
trip, trip_type, trip_temp, trend, throttle);
......
......@@ -38,6 +38,9 @@
#include <net/netlink.h>
#include <net/genetlink.h>
#define CREATE_TRACE_POINTS
#include <trace/events/thermal.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
......@@ -368,6 +371,8 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
if (tz->temperature < trip_temp)
return;
trace_thermal_zone_trip(tz, trip, trip_type);
if (tz->ops->notify)
tz->ops->notify(tz, trip, trip_type);
......@@ -463,6 +468,7 @@ static void update_temperature(struct thermal_zone_device *tz)
tz->temperature = temp;
mutex_unlock(&tz->lock);
trace_thermal_temperature(tz);
dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
tz->last_temperature, tz->temperature);
}
......@@ -1287,6 +1293,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
mutex_unlock(&cdev->lock);
cdev->ops->set_cur_state(cdev, target);
cdev->updated = true;
trace_cdev_update(cdev, target);
dev_dbg(&cdev->device, "set to state %lu\n", target);
}
EXPORT_SYMBOL(thermal_cdev_update);
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM thermal
#if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_THERMAL_H
#include <linux/thermal.h>
#include <linux/tracepoint.h>
TRACE_EVENT(thermal_temperature,
TP_PROTO(struct thermal_zone_device *tz),
TP_ARGS(tz),
TP_STRUCT__entry(
__string(thermal_zone, tz->type)
__field(int, id)
__field(int, temp_prev)
__field(int, temp)
),
TP_fast_assign(
__assign_str(thermal_zone, tz->type);
__entry->id = tz->id;
__entry->temp_prev = tz->last_temperature;
__entry->temp = tz->temperature;
),
TP_printk("thermal_zone=%s id=%d temp_prev=%d temp=%d",
__get_str(thermal_zone), __entry->id, __entry->temp_prev,
__entry->temp)
);
TRACE_EVENT(cdev_update,
TP_PROTO(struct thermal_cooling_device *cdev, unsigned long target),
TP_ARGS(cdev, target),
TP_STRUCT__entry(
__string(type, cdev->type)
__field(unsigned long, target)
),
TP_fast_assign(
__assign_str(type, cdev->type);
__entry->target = target;
),
TP_printk("type=%s target=%lu", __get_str(type), __entry->target)
);
TRACE_EVENT(thermal_zone_trip,
TP_PROTO(struct thermal_zone_device *tz, int trip,
enum thermal_trip_type trip_type),
TP_ARGS(tz, trip, trip_type),
TP_STRUCT__entry(
__string(thermal_zone, tz->type)
__field(int, id)
__field(int, trip)
__field(enum thermal_trip_type, trip_type)
),
TP_fast_assign(
__assign_str(thermal_zone, tz->type);
__entry->id = tz->id;
__entry->trip = trip;
__entry->trip_type = trip_type;
),
TP_printk("thermal_zone=%s id=%d trip=%d trip_type=%d",
__get_str(thermal_zone), __entry->id, __entry->trip,
__entry->trip_type)
);
#endif /* _TRACE_THERMAL_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment