ipq806x: add ipq806x specific tsens driver
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0063-2-tsens-support-configurable-interrupts.patch
1 From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001
2 From: Rajith Cherian <rajith@codeaurora.org>
3 Date: Wed, 1 Feb 2017 19:00:26 +0530
4 Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts
5
6 Provide support for adding configurable high and
7 configurable low trip temperatures. An interrupts is
8 also triggerred when these trip points are hit. The
9 interrupts can be activated or deactivated from sysfs.
10 This functionality is made available only if
11 CONFIG_THERMAL_WRITABLE_TRIPS is defined.
12
13 Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934
14 Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
15 ---
16  .../devicetree/bindings/thermal/qcom-tsens.txt     |  4 ++
17  drivers/thermal/of-thermal.c                       | 63 ++++++++++++++++++----
18  drivers/thermal/qcom/tsens.c                       | 43 ++++++++++++---
19  drivers/thermal/qcom/tsens.h                       | 11 ++++
20  drivers/thermal/thermal_core.c                     | 44 ++++++++++++++-
21  include/linux/thermal.h                            | 14 +++++
22  6 files changed, 162 insertions(+), 17 deletions(-)
23
24 diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
25 index f4a76f6..7c0a6a7 100644
26 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
27 +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
28 @@ -12,11 +12,15 @@ Required properties:
29  - Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
30  nvmem cells
31  
32 +Optional properties:
33 +- interrupts: Interrupt which gets triggered when threshold is hit
34 +
35  Example:
36  tsens: thermal-sensor@900000 {
37                 compatible = "qcom,msm8916-tsens";
38                 reg = <0x4a8000 0x2000>;
39                 nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
40                 nvmem-cell-names = "caldata", "calsel";
41 +               interrupts = <0 178 0>;
42                 #thermal-sensor-cells = <1>;
43         };
44 diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
45 index d04ec3b..d83697e 100644
46 --- a/drivers/thermal/of-thermal.c
47 +++ b/drivers/thermal/of-thermal.c
48 @@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
49  {
50         struct __thermal_zone *data = tz->devdata;
51  
52 -       if (!data->ops->get_temp)
53 +       if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED))
54                 return -EINVAL;
55  
56         return data->ops->get_temp(data->sensor_data, temp);
57 @@ -106,7 +106,8 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
58  {
59         struct __thermal_zone *data = tz->devdata;
60  
61 -       if (!data->ops || !data->ops->set_trips)
62 +       if (!data->ops || !data->ops->set_trips
63 +                       || (data->mode == THERMAL_DEVICE_DISABLED))
64                 return -EINVAL;
65  
66         return data->ops->set_trips(data->sensor_data, low, high);
67 @@ -192,6 +193,9 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
68  {
69         struct __thermal_zone *data = tz->devdata;
70  
71 +       if (data->mode == THERMAL_DEVICE_DISABLED)
72 +               return -EINVAL;
73 +
74         return data->ops->set_emul_temp(data->sensor_data, temp);
75  }
76  
77 @@ -200,7 +204,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
78  {
79         struct __thermal_zone *data = tz->devdata;
80  
81 -       if (!data->ops->get_trend)
82 +       if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED))
83                 return -EINVAL;
84  
85         return data->ops->get_trend(data->sensor_data, trip, trend);
86 @@ -286,7 +290,9 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
87         mutex_unlock(&tz->lock);
88  
89         data->mode = mode;
90 -       thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
91 +
92 +       if (mode == THERMAL_DEVICE_ENABLED)
93 +               thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
94  
95         return 0;
96  }
97 @@ -296,7 +302,8 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
98  {
99         struct __thermal_zone *data = tz->devdata;
100  
101 -       if (trip >= data->ntrips || trip < 0)
102 +       if (trip >= data->ntrips || trip < 0
103 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
104                 return -EDOM;
105  
106         *type = data->trips[trip].type;
107 @@ -304,12 +311,39 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
108         return 0;
109  }
110  
111 +static int of_thermal_activate_trip_type(struct thermal_zone_device *tz,
112 +                       int trip, enum thermal_trip_activation_mode mode)
113 +{
114 +       struct __thermal_zone *data = tz->devdata;
115 +
116 +       if (trip >= data->ntrips || trip < 0
117 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
118 +               return -EDOM;
119 +
120 +       /*
121 +        * The configurable_hi and configurable_lo trip points can be
122 +        * activated and deactivated.
123 +        */
124 +
125 +       if (data->ops->set_trip_activate) {
126 +               int ret;
127 +
128 +               ret = data->ops->set_trip_activate(data->sensor_data,
129 +                                                               trip, mode);
130 +               if (ret)
131 +                       return ret;
132 +       }
133 +
134 +       return 0;
135 +}
136 +
137  static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
138                                     int *temp)
139  {
140         struct __thermal_zone *data = tz->devdata;
141  
142 -       if (trip >= data->ntrips || trip < 0)
143 +       if (trip >= data->ntrips || trip < 0
144 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
145                 return -EDOM;
146  
147         *temp = data->trips[trip].temperature;
148 @@ -322,7 +356,8 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
149  {
150         struct __thermal_zone *data = tz->devdata;
151  
152 -       if (trip >= data->ntrips || trip < 0)
153 +       if (trip >= data->ntrips || trip < 0
154 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
155                 return -EDOM;
156  
157         if (data->ops->set_trip_temp) {
158 @@ -344,7 +379,8 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
159  {
160         struct __thermal_zone *data = tz->devdata;
161  
162 -       if (trip >= data->ntrips || trip < 0)
163 +       if (trip >= data->ntrips || trip < 0
164 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
165                 return -EDOM;
166  
167         *hyst = data->trips[trip].hysteresis;
168 @@ -357,7 +393,8 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
169  {
170         struct __thermal_zone *data = tz->devdata;
171  
172 -       if (trip >= data->ntrips || trip < 0)
173 +       if (trip >= data->ntrips || trip < 0
174 +                               || (data->mode == THERMAL_DEVICE_DISABLED))
175                 return -EDOM;
176  
177         /* thermal framework should take care of data->mask & (1 << trip) */
178 @@ -432,6 +469,9 @@ thermal_zone_of_add_sensor(struct device_node *zone,
179         if (ops->set_emul_temp)
180                 tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
181  
182 +       if (ops->set_trip_activate)
183 +               tzd->ops->set_trip_activate = of_thermal_activate_trip_type;
184 +
185         mutex_unlock(&tzd->lock);
186  
187         return tzd;
188 @@ -726,7 +766,10 @@ static const char * const trip_types[] = {
189         [THERMAL_TRIP_ACTIVE]   = "active",
190         [THERMAL_TRIP_PASSIVE]  = "passive",
191         [THERMAL_TRIP_HOT]      = "hot",
192 -       [THERMAL_TRIP_CRITICAL] = "critical",
193 +       [THERMAL_TRIP_CRITICAL] = "critical_high",
194 +       [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi",
195 +       [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo",
196 +       [THERMAL_TRIP_CRITICAL_LOW] = "critical_low",
197  };
198  
199  /**
200 diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
201 index 2d25593..ac68af3 100644
202 --- a/drivers/thermal/qcom/tsens.c
203 +++ b/drivers/thermal/qcom/tsens.c
204 @@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, int *temp)
205  
206  static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
207  {
208 -       const struct tsens_sensor *s = p;
209 +       struct tsens_sensor *s = p;
210         struct tsens_device *tmdev = s->tmdev;
211  
212         if (tmdev->ops->get_trend)
213 @@ -40,9 +40,10 @@ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
214         return -ENOTSUPP;
215  }
216  
217 -static int  __maybe_unused tsens_suspend(struct device *dev)
218 +static int  __maybe_unused tsens_suspend(void *data)
219  {
220 -       struct tsens_device *tmdev = dev_get_drvdata(dev);
221 +       struct tsens_sensor *s = data;
222 +       struct tsens_device *tmdev = s->tmdev;
223  
224         if (tmdev->ops && tmdev->ops->suspend)
225                 return tmdev->ops->suspend(tmdev);
226 @@ -50,9 +51,10 @@ static int  __maybe_unused tsens_suspend(struct device *dev)
227         return 0;
228  }
229  
230 -static int __maybe_unused tsens_resume(struct device *dev)
231 +static int __maybe_unused tsens_resume(void *data)
232  {
233 -       struct tsens_device *tmdev = dev_get_drvdata(dev);
234 +       struct tsens_sensor *s = data;
235 +       struct tsens_device *tmdev = s->tmdev;
236  
237         if (tmdev->ops && tmdev->ops->resume)
238                 return tmdev->ops->resume(tmdev);
239 @@ -60,6 +62,30 @@ static int __maybe_unused tsens_resume(struct device *dev)
240         return 0;
241  }
242  
243 +static int  __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp)
244 +{
245 +       struct tsens_sensor *s = data;
246 +       struct tsens_device *tmdev = s->tmdev;
247 +
248 +       if (tmdev->ops && tmdev->ops->set_trip_temp)
249 +               return tmdev->ops->set_trip_temp(s, trip, temp);
250 +
251 +       return 0;
252 +}
253 +
254 +static int __maybe_unused tsens_activate_trip_type(void *data, int trip,
255 +                                       enum thermal_trip_activation_mode mode)
256 +{
257 +       struct tsens_sensor *s = data;
258 +       struct tsens_device *tmdev = s->tmdev;
259 +
260 +       if (tmdev->ops && tmdev->ops->set_trip_activate)
261 +               return tmdev->ops->set_trip_activate(s, trip, mode);
262 +
263 +       return 0;
264 +}
265 +
266 +
267  static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
268  
269  static const struct of_device_id tsens_table[] = {
270 @@ -83,6 +109,8 @@ MODULE_DEVICE_TABLE(of, tsens_table);
271  static const struct thermal_zone_of_device_ops tsens_of_ops = {
272         .get_temp = tsens_get_temp,
273         .get_trend = tsens_get_trend,
274 +       .set_trip_temp = tsens_set_trip_temp,
275 +       .set_trip_activate = tsens_activate_trip_type,
276  };
277  
278  static int tsens_register(struct tsens_device *tmdev)
279 @@ -131,7 +159,7 @@ static int tsens_probe(struct platform_device *pdev)
280         if (id)
281                 data = id->data;
282         else
283 -               data = &data_8960;
284 +               return -EINVAL;
285  
286         if (data->num_sensors <= 0) {
287                 dev_err(dev, "invalid number of sensors\n");
288 @@ -146,6 +174,9 @@ static int tsens_probe(struct platform_device *pdev)
289         tmdev->dev = dev;
290         tmdev->num_sensors = data->num_sensors;
291         tmdev->ops = data->ops;
292 +
293 +       tmdev->tsens_irq = platform_get_irq(pdev, 0);
294 +
295         for (i = 0;  i < tmdev->num_sensors; i++) {
296                 if (data->hw_ids)
297                         tmdev->sensor[i].hw_id = data->hw_ids[i];
298 diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
299 index 31279a2..54bbdc0 100644
300 --- a/drivers/thermal/qcom/tsens.h
301 +++ b/drivers/thermal/qcom/tsens.h
302 @@ -24,9 +24,12 @@ struct tsens_device;
303  struct tsens_sensor {
304         struct tsens_device             *tmdev;
305         struct thermal_zone_device      *tzd;
306 +       struct work_struct              notify_work;
307         int                             offset;
308         int                             id;
309         int                             hw_id;
310 +       int                             calib_data;
311 +       int                             calib_data_backup;
312         int                             slope;
313         u32                             status;
314  };
315 @@ -41,6 +44,9 @@ struct tsens_sensor {
316   * @suspend: Function to suspend the tsens device
317   * @resume: Function to resume the tsens device
318   * @get_trend: Function to get the thermal/temp trend
319 + * @set_trip_temp: Function to set trip temp
320 + * @get_trip_temp: Function to get trip temp
321 + * @set_trip_activate: Function to activate trip points
322   */
323  struct tsens_ops {
324         /* mandatory callbacks */
325 @@ -53,6 +59,9 @@ struct tsens_ops {
326         int (*suspend)(struct tsens_device *);
327         int (*resume)(struct tsens_device *);
328         int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
329 +       int (*set_trip_temp)(void *, int, int);
330 +       int (*set_trip_activate)(void *, int,
331 +                                       enum thermal_trip_activation_mode);
332  };
333  
334  /**
335 @@ -76,11 +85,13 @@ struct tsens_context {
336  struct tsens_device {
337         struct device                   *dev;
338         u32                             num_sensors;
339 +       u32                             tsens_irq;
340         struct regmap                   *map;
341         struct regmap_field             *status_field;
342         struct tsens_context            ctx;
343         bool                            trdy;
344         const struct tsens_ops          *ops;
345 +       struct work_struct              tsens_work;
346         struct tsens_sensor             sensor[0];
347  };
348  
349 diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
350 index 226b0b4..20bd624 100644
351 --- a/drivers/thermal/thermal_core.c
352 +++ b/drivers/thermal/thermal_core.c
353 @@ -732,12 +732,48 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
354                 return sprintf(buf, "passive\n");
355         case THERMAL_TRIP_ACTIVE:
356                 return sprintf(buf, "active\n");
357 +       case THERMAL_TRIP_CONFIGURABLE_HI:
358 +               return sprintf(buf, "configurable_hi\n");
359 +       case THERMAL_TRIP_CONFIGURABLE_LOW:
360 +               return sprintf(buf, "configurable_low\n");
361 +       case THERMAL_TRIP_CRITICAL_LOW:
362 +               return sprintf(buf, "critical_low\n");
363         default:
364                 return sprintf(buf, "unknown\n");
365         }
366  }
367  
368  static ssize_t
369 +trip_point_type_activate(struct device *dev, struct device_attribute *attr,
370 +                                               const char *buf, size_t count)
371 +{
372 +       struct thermal_zone_device *tz = to_thermal_zone(dev);
373 +       int trip, ret;
374 +       char *enabled = "enabled";
375 +       char *disabled = "disabled";
376 +
377 +       if (!tz->ops->set_trip_activate)
378 +               return -EPERM;
379 +
380 +       if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
381 +               return -EINVAL;
382 +
383 +       if (!strncmp(buf, enabled, strlen(enabled)))
384 +               ret = tz->ops->set_trip_activate(tz, trip,
385 +                               THERMAL_TRIP_ACTIVATION_ENABLED);
386 +       else if (!strncmp(buf, disabled, strlen(disabled)))
387 +               ret = tz->ops->set_trip_activate(tz, trip,
388 +                               THERMAL_TRIP_ACTIVATION_DISABLED);
389 +       else
390 +               ret = -EINVAL;
391 +
392 +       if (ret)
393 +               return ret;
394 +
395 +       return count;
396 +}
397 +
398 +static ssize_t
399  trip_point_temp_store(struct device *dev, struct device_attribute *attr,
400                      const char *buf, size_t count)
401  {
402 @@ -1321,7 +1357,7 @@ thermal_cooling_device_weight_store(struct device *dev,
403   */
404  int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
405                                      int trip,
406 -                                    struct thermal_cooling_device *cdev,
407 +                                       struct thermal_cooling_device *cdev,
408                                      unsigned long upper, unsigned long lower,
409                                      unsigned int weight)
410  {
411 @@ -1772,6 +1808,12 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
412                 tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
413                 tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
414  
415 +               if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) {
416 +                       tz->trip_type_attrs[indx].attr.store
417 +                                               = trip_point_type_activate;
418 +                       tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR;
419 +               }
420 +
421                 device_create_file(&tz->device,
422                                    &tz->trip_type_attrs[indx].attr);
423  
424 diff --git a/include/linux/thermal.h b/include/linux/thermal.h
425 index 511182a..510a087 100644
426 --- a/include/linux/thermal.h
427 +++ b/include/linux/thermal.h
428 @@ -77,11 +77,19 @@ enum thermal_device_mode {
429         THERMAL_DEVICE_ENABLED,
430  };
431  
432 +enum thermal_trip_activation_mode {
433 +       THERMAL_TRIP_ACTIVATION_DISABLED = 0,
434 +       THERMAL_TRIP_ACTIVATION_ENABLED,
435 +};
436 +
437  enum thermal_trip_type {
438         THERMAL_TRIP_ACTIVE = 0,
439         THERMAL_TRIP_PASSIVE,
440         THERMAL_TRIP_HOT,
441         THERMAL_TRIP_CRITICAL,
442 +       THERMAL_TRIP_CONFIGURABLE_HI,
443 +       THERMAL_TRIP_CONFIGURABLE_LOW,
444 +       THERMAL_TRIP_CRITICAL_LOW,
445  };
446  
447  enum thermal_trend {
448 @@ -118,6 +126,8 @@ struct thermal_zone_device_ops {
449                 enum thermal_trip_type *);
450         int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
451         int (*set_trip_temp) (struct thermal_zone_device *, int, int);
452 +       int (*set_trip_activate) (struct thermal_zone_device *, int,
453 +                                       enum thermal_trip_activation_mode);
454         int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
455         int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
456         int (*get_crit_temp) (struct thermal_zone_device *, int *);
457 @@ -360,6 +370,8 @@ struct thermal_genl_event {
458   *                temperature.
459   * @set_trip_temp: a pointer to a function that sets the trip temperature on
460   *                hardware.
461 + * @activate_trip_type: a pointer to a function to enable/disable trip
462 + *             temperature interrupts
463   */
464  struct thermal_zone_of_device_ops {
465         int (*get_temp)(void *, int *);
466 @@ -367,6 +379,8 @@ struct thermal_zone_of_device_ops {
467         int (*set_trips)(void *, int, int);
468         int (*set_emul_temp)(void *, int);
469         int (*set_trip_temp)(void *, int, int);
470 +       int (*set_trip_activate)(void *, int,
471 +                               enum thermal_trip_activation_mode);
472  };
473  
474  /**