openwrt/target/linux/ipq806x/patches-4.9/0063-2-tsens-support-configurable-interrupts.patch

475 lines
15 KiB
Diff

From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001
From: Rajith Cherian <rajith@codeaurora.org>
Date: Wed, 1 Feb 2017 19:00:26 +0530
Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts
Provide support for adding configurable high and
configurable low trip temperatures. An interrupts is
also triggerred when these trip points are hit. The
interrupts can be activated or deactivated from sysfs.
This functionality is made available only if
CONFIG_THERMAL_WRITABLE_TRIPS is defined.
Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934
Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
---
.../devicetree/bindings/thermal/qcom-tsens.txt | 4 ++
drivers/thermal/of-thermal.c | 63 ++++++++++++++++++----
drivers/thermal/qcom/tsens.c | 43 ++++++++++++---
drivers/thermal/qcom/tsens.h | 11 ++++
drivers/thermal/thermal_core.c | 44 ++++++++++++++-
include/linux/thermal.h | 14 +++++
6 files changed, 162 insertions(+), 17 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
index f4a76f6..7c0a6a7 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
@@ -12,11 +12,15 @@ Required properties:
- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
nvmem cells
+Optional properties:
+- interrupts: Interrupt which gets triggered when threshold is hit
+
Example:
tsens: thermal-sensor@900000 {
compatible = "qcom,msm8916-tsens";
reg = <0x4a8000 0x2000>;
nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
nvmem-cell-names = "caldata", "calsel";
+ interrupts = <0 178 0>;
#thermal-sensor-cells = <1>;
};
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d04ec3b..d83697e 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_temp)
+ if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->get_temp(data->sensor_data, temp);
@@ -106,7 +106,8 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops || !data->ops->set_trips)
+ if (!data->ops || !data->ops->set_trips
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->set_trips(data->sensor_data, low, high);
@@ -192,6 +193,9 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
+ if (data->mode == THERMAL_DEVICE_DISABLED)
+ return -EINVAL;
+
return data->ops->set_emul_temp(data->sensor_data, temp);
}
@@ -200,7 +204,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_trend)
+ if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->get_trend(data->sensor_data, trip, trend);
@@ -286,7 +290,9 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
mutex_unlock(&tz->lock);
data->mode = mode;
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ if (mode == THERMAL_DEVICE_ENABLED)
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
return 0;
}
@@ -296,7 +302,8 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*type = data->trips[trip].type;
@@ -304,12 +311,39 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
return 0;
}
+static int of_thermal_activate_trip_type(struct thermal_zone_device *tz,
+ int trip, enum thermal_trip_activation_mode mode)
+{
+ struct __thermal_zone *data = tz->devdata;
+
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
+ return -EDOM;
+
+ /*
+ * The configurable_hi and configurable_lo trip points can be
+ * activated and deactivated.
+ */
+
+ if (data->ops->set_trip_activate) {
+ int ret;
+
+ ret = data->ops->set_trip_activate(data->sensor_data,
+ trip, mode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
int *temp)
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*temp = data->trips[trip].temperature;
@@ -322,7 +356,8 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
if (data->ops->set_trip_temp) {
@@ -344,7 +379,8 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*hyst = data->trips[trip].hysteresis;
@@ -357,7 +393,8 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
/* thermal framework should take care of data->mask & (1 << trip) */
@@ -432,6 +469,9 @@ thermal_zone_of_add_sensor(struct device_node *zone,
if (ops->set_emul_temp)
tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+ if (ops->set_trip_activate)
+ tzd->ops->set_trip_activate = of_thermal_activate_trip_type;
+
mutex_unlock(&tzd->lock);
return tzd;
@@ -726,7 +766,10 @@ static const char * const trip_types[] = {
[THERMAL_TRIP_ACTIVE] = "active",
[THERMAL_TRIP_PASSIVE] = "passive",
[THERMAL_TRIP_HOT] = "hot",
- [THERMAL_TRIP_CRITICAL] = "critical",
+ [THERMAL_TRIP_CRITICAL] = "critical_high",
+ [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi",
+ [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo",
+ [THERMAL_TRIP_CRITICAL_LOW] = "critical_low",
};
/**
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 2d25593..ac68af3 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, int *temp)
static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
{
- const struct tsens_sensor *s = p;
+ struct tsens_sensor *s = p;
struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops->get_trend)
@@ -40,9 +40,10 @@ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
return -ENOTSUPP;
}
-static int __maybe_unused tsens_suspend(struct device *dev)
+static int __maybe_unused tsens_suspend(void *data)
{
- struct tsens_device *tmdev = dev_get_drvdata(dev);
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops && tmdev->ops->suspend)
return tmdev->ops->suspend(tmdev);
@@ -50,9 +51,10 @@ static int __maybe_unused tsens_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tsens_resume(struct device *dev)
+static int __maybe_unused tsens_resume(void *data)
{
- struct tsens_device *tmdev = dev_get_drvdata(dev);
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops && tmdev->ops->resume)
return tmdev->ops->resume(tmdev);
@@ -60,6 +62,30 @@ static int __maybe_unused tsens_resume(struct device *dev)
return 0;
}
+static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp)
+{
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
+
+ if (tmdev->ops && tmdev->ops->set_trip_temp)
+ return tmdev->ops->set_trip_temp(s, trip, temp);
+
+ return 0;
+}
+
+static int __maybe_unused tsens_activate_trip_type(void *data, int trip,
+ enum thermal_trip_activation_mode mode)
+{
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
+
+ if (tmdev->ops && tmdev->ops->set_trip_activate)
+ return tmdev->ops->set_trip_activate(s, trip, mode);
+
+ return 0;
+}
+
+
static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
static const struct of_device_id tsens_table[] = {
@@ -83,6 +109,8 @@ 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,
+ .set_trip_temp = tsens_set_trip_temp,
+ .set_trip_activate = tsens_activate_trip_type,
};
static int tsens_register(struct tsens_device *tmdev)
@@ -131,7 +159,7 @@ static int tsens_probe(struct platform_device *pdev)
if (id)
data = id->data;
else
- data = &data_8960;
+ return -EINVAL;
if (data->num_sensors <= 0) {
dev_err(dev, "invalid number of sensors\n");
@@ -146,6 +174,9 @@ static int tsens_probe(struct platform_device *pdev)
tmdev->dev = dev;
tmdev->num_sensors = data->num_sensors;
tmdev->ops = data->ops;
+
+ tmdev->tsens_irq = platform_get_irq(pdev, 0);
+
for (i = 0; i < tmdev->num_sensors; i++) {
if (data->hw_ids)
tmdev->sensor[i].hw_id = data->hw_ids[i];
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 31279a2..54bbdc0 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -24,9 +24,12 @@ struct tsens_device;
struct tsens_sensor {
struct tsens_device *tmdev;
struct thermal_zone_device *tzd;
+ struct work_struct notify_work;
int offset;
int id;
int hw_id;
+ int calib_data;
+ int calib_data_backup;
int slope;
u32 status;
};
@@ -41,6 +44,9 @@ struct tsens_sensor {
* @suspend: Function to suspend the tsens device
* @resume: Function to resume the tsens device
* @get_trend: Function to get the thermal/temp trend
+ * @set_trip_temp: Function to set trip temp
+ * @get_trip_temp: Function to get trip temp
+ * @set_trip_activate: Function to activate trip points
*/
struct tsens_ops {
/* mandatory callbacks */
@@ -53,6 +59,9 @@ struct tsens_ops {
int (*suspend)(struct tsens_device *);
int (*resume)(struct tsens_device *);
int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
+ int (*set_trip_temp)(void *, int, int);
+ int (*set_trip_activate)(void *, int,
+ enum thermal_trip_activation_mode);
};
/**
@@ -76,11 +85,13 @@ struct tsens_context {
struct tsens_device {
struct device *dev;
u32 num_sensors;
+ u32 tsens_irq;
struct regmap *map;
struct regmap_field *status_field;
struct tsens_context ctx;
bool trdy;
const struct tsens_ops *ops;
+ struct work_struct tsens_work;
struct tsens_sensor sensor[0];
};
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 226b0b4..20bd624 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -732,12 +732,48 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ return sprintf(buf, "configurable_hi\n");
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ return sprintf(buf, "configurable_low\n");
+ case THERMAL_TRIP_CRITICAL_LOW:
+ return sprintf(buf, "critical_low\n");
default:
return sprintf(buf, "unknown\n");
}
}
static ssize_t
+trip_point_type_activate(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+ char *enabled = "enabled";
+ char *disabled = "disabled";
+
+ if (!tz->ops->set_trip_activate)
+ return -EPERM;
+
+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+ return -EINVAL;
+
+ if (!strncmp(buf, enabled, strlen(enabled)))
+ ret = tz->ops->set_trip_activate(tz, trip,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ else if (!strncmp(buf, disabled, strlen(disabled)))
+ ret = tz->ops->set_trip_activate(tz, trip,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ else
+ ret = -EINVAL;
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t
trip_point_temp_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1321,7 +1357,7 @@ thermal_cooling_device_weight_store(struct device *dev,
*/
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip,
- struct thermal_cooling_device *cdev,
+ struct thermal_cooling_device *cdev,
unsigned long upper, unsigned long lower,
unsigned int weight)
{
@@ -1772,6 +1808,12 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
+ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) {
+ tz->trip_type_attrs[indx].attr.store
+ = trip_point_type_activate;
+ tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR;
+ }
+
device_create_file(&tz->device,
&tz->trip_type_attrs[indx].attr);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 511182a..510a087 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -77,11 +77,19 @@ enum thermal_device_mode {
THERMAL_DEVICE_ENABLED,
};
+enum thermal_trip_activation_mode {
+ THERMAL_TRIP_ACTIVATION_DISABLED = 0,
+ THERMAL_TRIP_ACTIVATION_ENABLED,
+};
+
enum thermal_trip_type {
THERMAL_TRIP_ACTIVE = 0,
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_TRIP_CRITICAL_LOW,
};
enum thermal_trend {
@@ -118,6 +126,8 @@ struct thermal_zone_device_ops {
enum thermal_trip_type *);
int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
int (*set_trip_temp) (struct thermal_zone_device *, int, int);
+ int (*set_trip_activate) (struct thermal_zone_device *, int,
+ enum thermal_trip_activation_mode);
int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
int (*get_crit_temp) (struct thermal_zone_device *, int *);
@@ -360,6 +370,8 @@ struct thermal_genl_event {
* temperature.
* @set_trip_temp: a pointer to a function that sets the trip temperature on
* hardware.
+ * @activate_trip_type: a pointer to a function to enable/disable trip
+ * temperature interrupts
*/
struct thermal_zone_of_device_ops {
int (*get_temp)(void *, int *);
@@ -367,6 +379,8 @@ struct thermal_zone_of_device_ops {
int (*set_trips)(void *, int, int);
int (*set_emul_temp)(void *, int);
int (*set_trip_temp)(void *, int, int);
+ int (*set_trip_activate)(void *, int,
+ enum thermal_trip_activation_mode);
};
/**