Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal into eduardo-soc
This commit is contained in:
commit
62ebb7b166
|
@ -1,7 +1,10 @@
|
|||
* 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);
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
#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>
|
Loading…
Reference in New Issue