From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001 From: Rajith Cherian 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 --- .../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(-) --- 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>; }; --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct th { 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 t { 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(stru { 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 t { 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); @@ -289,7 +293,9 @@ static int of_thermal_set_mode(struct th 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; } @@ -299,7 +305,8 @@ static int of_thermal_get_trip_type(stru { 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; @@ -307,12 +314,39 @@ static int of_thermal_get_trip_type(stru 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; @@ -325,7 +359,8 @@ static int of_thermal_set_trip_temp(stru { 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) { @@ -347,7 +382,8 @@ static int of_thermal_get_trip_hyst(stru { 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; @@ -360,7 +396,8 @@ static int of_thermal_set_trip_hyst(stru { 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) */ @@ -435,6 +472,9 @@ thermal_zone_of_add_sensor(struct device 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; @@ -729,7 +769,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", }; /** --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, in 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 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 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(s 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_d 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_d 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]; --- 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]; }; --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -115,12 +115,48 @@ trip_point_type_show(struct device *dev, 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) { @@ -562,6 +598,12 @@ static int create_trip_attrs(struct ther tz->trip_type_attrs[indx].attr.show = trip_point_type_show; attrs[indx] = &tz->trip_type_attrs[indx].attr.attr; + 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; + } + /* create trip temp attribute */ snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH, "trip_point_%d_temp", indx); --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -78,11 +78,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 { @@ -120,6 +128,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 *); @@ -363,6 +373,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 *); @@ -370,6 +382,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); }; /**