blob: 13b183d563973c56a3710d374f811fc5b351b310 [file] [log] [blame]
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -08001/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
Siddartha Mohanadosscd8aa0b2017-04-06 15:17:46 -07004 * it under the terms of the GNU General Public License version 2 and
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -08005 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/slab.h>
17#include <linux/err.h>
18#include <linux/of.h>
19#include <linux/vmalloc.h>
20#include "tsens.h"
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070021#include "thermal_core.h"
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080022
23#define TSENS_DRIVER_NAME "msm-tsens"
24
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070025#define TSENS_TM_INT_EN(n) ((n) + 0x4)
26#define TSENS_TM_CRITICAL_INT_STATUS(n) ((n) + 0x14)
27#define TSENS_TM_CRITICAL_INT_CLEAR(n) ((n) + 0x18)
28#define TSENS_TM_CRITICAL_INT_MASK(n) ((n) + 0x1c)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080029#define TSENS_TM_CRITICAL_WD_BARK BIT(31)
30#define TSENS_TM_CRITICAL_CYCLE_MONITOR BIT(30)
31#define TSENS_TM_CRITICAL_INT_EN BIT(2)
32#define TSENS_TM_UPPER_INT_EN BIT(1)
33#define TSENS_TM_LOWER_INT_EN BIT(0)
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070034#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n) ((n) + 0x20)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080035#define TSENS_TM_SN_ADDR_OFFSET 0x4
36#define TSENS_TM_UPPER_THRESHOLD_SET(n) ((n) << 12)
37#define TSENS_TM_UPPER_THRESHOLD_VALUE_SHIFT(n) ((n) >> 12)
38#define TSENS_TM_LOWER_THRESHOLD_VALUE(n) ((n) & 0xfff)
39#define TSENS_TM_UPPER_THRESHOLD_VALUE(n) (((n) & 0xfff000) >> 12)
40#define TSENS_TM_UPPER_THRESHOLD_MASK 0xfff000
41#define TSENS_TM_LOWER_THRESHOLD_MASK 0xfff
42#define TSENS_TM_UPPER_THRESHOLD_SHIFT 12
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070043#define TSENS_TM_SN_CRITICAL_THRESHOLD(n) ((n) + 0x60)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080044#define TSENS_STATUS_ADDR_OFFSET 2
45#define TSENS_TM_UPPER_INT_MASK(n) (((n) & 0xffff0000) >> 16)
46#define TSENS_TM_LOWER_INT_MASK(n) ((n) & 0xffff)
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070047#define TSENS_TM_UPPER_LOWER_INT_STATUS(n) ((n) + 0x8)
48#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n) ((n) + 0xc)
49#define TSENS_TM_UPPER_LOWER_INT_MASK(n) ((n) + 0x10)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080050#define TSENS_TM_UPPER_INT_SET(n) (1 << (n + 16))
51#define TSENS_TM_SN_CRITICAL_THRESHOLD_MASK 0xfff
52#define TSENS_TM_SN_STATUS_VALID_BIT BIT(21)
53#define TSENS_TM_SN_STATUS_CRITICAL_STATUS BIT(19)
54#define TSENS_TM_SN_STATUS_UPPER_STATUS BIT(18)
55#define TSENS_TM_SN_STATUS_LOWER_STATUS BIT(17)
56#define TSENS_TM_SN_LAST_TEMP_MASK 0xfff
57#define TSENS_TM_CODE_BIT_MASK 0xfff
58#define TSENS_TM_CODE_SIGN_BIT 0x800
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070059#define TSENS_TM_SCALE_DECI_MILLIDEG 100
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080060
61#define TSENS_EN BIT(0)
62
63static void msm_tsens_convert_temp(int last_temp, int *temp)
64{
65 int code_mask = ~TSENS_TM_CODE_BIT_MASK;
66
67 if (last_temp & TSENS_TM_CODE_SIGN_BIT) {
68 /* Sign extension for negative value */
69 last_temp |= code_mask;
70 }
71
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070072 *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080073}
74
75static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
76{
77 struct tsens_device *tmdev = NULL;
78 unsigned int code;
79 void __iomem *sensor_addr;
80 int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
81
82 if (!sensor)
83 return -EINVAL;
84
85 tmdev = sensor->tmdev;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070086 sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080087
88 code = readl_relaxed_no_log(sensor_addr +
89 (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
90 last_temp = code & TSENS_TM_SN_LAST_TEMP_MASK;
91
92 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
93 msm_tsens_convert_temp(last_temp, temp);
94 return 0;
95 }
96
97 code = readl_relaxed_no_log(sensor_addr +
98 (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
99 last_temp2 = code & TSENS_TM_SN_LAST_TEMP_MASK;
100 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
101 last_temp = last_temp2;
102 msm_tsens_convert_temp(last_temp, temp);
103 return 0;
104 }
105
106 code = readl_relaxed_no_log(sensor_addr +
107 (sensor->hw_id <<
108 TSENS_STATUS_ADDR_OFFSET));
109 last_temp3 = code & TSENS_TM_SN_LAST_TEMP_MASK;
110 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
111 last_temp = last_temp3;
112 msm_tsens_convert_temp(last_temp, temp);
113 return 0;
114 }
115
116 if (last_temp == last_temp2)
117 last_temp = last_temp2;
118 else if (last_temp2 == last_temp3)
119 last_temp = last_temp3;
120
121 msm_tsens_convert_temp(last_temp, temp);
122
123 if (tmdev->ops->dbg)
124 tmdev->ops->dbg(tmdev, (u32) sensor->hw_id,
125 TSENS_DBG_LOG_TEMP_READS, temp);
126
127 return 0;
128}
129
130static int tsens_tm_activate_trip_type(struct tsens_sensor *tm_sensor,
131 int trip, enum thermal_trip_activation_mode mode)
132{
133 struct tsens_device *tmdev = NULL;
134 unsigned int reg_cntl, mask;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800135 int rc = 0;
136
137 /* clear the interrupt and unmask */
138 if (!tm_sensor || trip < 0)
139 return -EINVAL;
140
141 tmdev = tm_sensor->tmdev;
142 if (!tmdev)
143 return -EINVAL;
144
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700145
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800146 mask = (tm_sensor->hw_id);
147 switch (trip) {
148 case THERMAL_TRIP_CRITICAL:
149 tmdev->sensor[tm_sensor->hw_id].
150 thr_state.crit_th_state = mode;
151 reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700152 (tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800153 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
154 writel_relaxed(reg_cntl | (1 << mask),
155 (TSENS_TM_CRITICAL_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700156 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800157 else
158 writel_relaxed(reg_cntl & ~(1 << mask),
159 (TSENS_TM_CRITICAL_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700160 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800161 break;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700162 case THERMAL_TRIP_CONFIGURABLE_HI:
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800163 tmdev->sensor[tm_sensor->hw_id].
164 thr_state.high_th_state = mode;
165 reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700166 (tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800167 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
168 writel_relaxed(reg_cntl |
169 (TSENS_TM_UPPER_INT_SET(mask)),
170 (TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700171 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800172 else
173 writel_relaxed(reg_cntl &
174 ~(TSENS_TM_UPPER_INT_SET(mask)),
175 (TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700176 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800177 break;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700178 case THERMAL_TRIP_CONFIGURABLE_LOW:
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800179 tmdev->sensor[tm_sensor->hw_id].
180 thr_state.low_th_state = mode;
181 reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700182 (tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800183 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
184 writel_relaxed(reg_cntl | (1 << mask),
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700185 (TSENS_TM_UPPER_LOWER_INT_MASK
186 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800187 else
188 writel_relaxed(reg_cntl & ~(1 << mask),
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700189 (TSENS_TM_UPPER_LOWER_INT_MASK
190 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800191 break;
192 default:
193 rc = -EINVAL;
194 }
195
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800196 /* Activate and enable the respective trip threshold setting */
197 mb();
198
199 return rc;
200}
201
202static int tsens2xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700203 int low_temp, int high_temp)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800204{
205 unsigned int reg_cntl;
206 unsigned long flags;
207 struct tsens_device *tmdev = NULL;
208 int rc = 0;
209
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700210 if (!tm_sensor)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800211 return -EINVAL;
212
213 tmdev = tm_sensor->tmdev;
214 if (!tmdev)
215 return -EINVAL;
216
217 spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700218
219 if (high_temp != INT_MAX) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800220 tmdev->sensor[tm_sensor->hw_id].
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700221 thr_state.high_temp = high_temp;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800222 reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700223 (tmdev->tsens_tm_addr)) +
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800224 (tm_sensor->hw_id *
225 TSENS_TM_SN_ADDR_OFFSET));
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700226 high_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
227 high_temp = TSENS_TM_UPPER_THRESHOLD_SET(high_temp);
228 high_temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800229 reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700230 writel_relaxed(reg_cntl | high_temp,
231 (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
232 (tmdev->tsens_tm_addr) +
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800233 (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800234 }
235
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700236 if (low_temp != INT_MIN) {
237 tmdev->sensor[tm_sensor->hw_id].
238 thr_state.low_temp = low_temp;
239 reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
240 (tmdev->tsens_tm_addr)) +
241 (tm_sensor->hw_id *
242 TSENS_TM_SN_ADDR_OFFSET));
243 low_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
244 low_temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
245 reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
246 writel_relaxed(reg_cntl | low_temp,
247 (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
248 (tmdev->tsens_tm_addr) +
249 (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
250 }
251
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800252 /* Set trip temperature thresholds */
253 mb();
254
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700255 if (high_temp != INT_MAX) {
256 rc = tsens_tm_activate_trip_type(tm_sensor,
257 THERMAL_TRIP_CONFIGURABLE_HI,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800258 THERMAL_TRIP_ACTIVATION_ENABLED);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700259 if (rc) {
Siddartha Mohanadossf10a5a32017-04-19 09:31:39 -0700260 pr_err("trip high enable error :%d\n", rc);
261 goto fail;
262 }
263 } else {
264 rc = tsens_tm_activate_trip_type(tm_sensor,
265 THERMAL_TRIP_CONFIGURABLE_HI,
266 THERMAL_TRIP_ACTIVATION_DISABLED);
267 if (rc) {
268 pr_err("trip high disable error :%d\n", rc);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700269 goto fail;
270 }
271 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800272
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700273 if (low_temp != INT_MIN) {
274 rc = tsens_tm_activate_trip_type(tm_sensor,
275 THERMAL_TRIP_CONFIGURABLE_LOW,
276 THERMAL_TRIP_ACTIVATION_ENABLED);
277 if (rc) {
Siddartha Mohanadossf10a5a32017-04-19 09:31:39 -0700278 pr_err("trip low enable activation error :%d\n", rc);
279 goto fail;
280 }
281 } else {
282 rc = tsens_tm_activate_trip_type(tm_sensor,
283 THERMAL_TRIP_CONFIGURABLE_LOW,
284 THERMAL_TRIP_ACTIVATION_DISABLED);
285 if (rc) {
286 pr_err("trip low disable error :%d\n", rc);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700287 goto fail;
288 }
289 }
290
291fail:
292 spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800293 return rc;
294}
295
296static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data)
297{
298 struct tsens_device *tm = data;
299 unsigned int i, status;
300 unsigned long flags;
301 void __iomem *sensor_status_addr;
302 void __iomem *sensor_int_mask_addr;
303 void __iomem *sensor_critical_addr;
304 void __iomem *wd_critical_addr;
305 int wd_mask;
306
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700307 sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800308 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700309 TSENS_TM_CRITICAL_INT_MASK(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800310 sensor_critical_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700311 TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800312 wd_critical_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700313 TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800314
315 if (tm->ctrl_data->wd_bark) {
316 wd_mask = readl_relaxed(wd_critical_addr);
317 if (wd_mask & TSENS_TM_CRITICAL_WD_BARK) {
318 /*
319 * Clear watchdog interrupt and
320 * increment global wd count
321 */
322 writel_relaxed(wd_mask | TSENS_TM_CRITICAL_WD_BARK,
323 (TSENS_TM_CRITICAL_INT_CLEAR
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700324 (tm->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800325 writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
326 (TSENS_TM_CRITICAL_INT_CLEAR
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700327 (tm->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800328 tm->tsens_dbg.tsens_critical_wd_cnt++;
329 return IRQ_HANDLED;
330 }
331 }
332
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700333 for (i = 0; i < TSENS_MAX_SENSORS; i++) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800334 int int_mask, int_mask_val;
335 u32 addr_offset;
336
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700337 if (IS_ERR(tm->sensor[i].tzd))
338 continue;
339
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800340 spin_lock_irqsave(&tm->tsens_crit_lock, flags);
341 addr_offset = tm->sensor[i].hw_id *
342 TSENS_TM_SN_ADDR_OFFSET;
343 status = readl_relaxed(sensor_status_addr + addr_offset);
344 int_mask = readl_relaxed(sensor_int_mask_addr);
345
346 if ((status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) &&
347 !(int_mask & (1 << tm->sensor[i].hw_id))) {
348 int_mask = readl_relaxed(sensor_int_mask_addr);
349 int_mask_val = (1 << tm->sensor[i].hw_id);
350 /* Mask the corresponding interrupt for the sensors */
351 writel_relaxed(int_mask | int_mask_val,
352 TSENS_TM_CRITICAL_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700353 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800354 /* Clear the corresponding sensors interrupt */
355 writel_relaxed(int_mask_val,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700356 TSENS_TM_CRITICAL_INT_CLEAR
357 (tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800358 writel_relaxed(0,
359 TSENS_TM_CRITICAL_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700360 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800361 tm->sensor[i].thr_state.
362 crit_th_state = THERMAL_DEVICE_DISABLED;
363 }
364 spin_unlock_irqrestore(&tm->tsens_crit_lock, flags);
365 }
366
367 /* Mask critical interrupt */
368 mb();
369
370 return IRQ_HANDLED;
371}
372
373static irqreturn_t tsens_tm_irq_thread(int irq, void *data)
374{
375 struct tsens_device *tm = data;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700376 unsigned int i, status, threshold, temp;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800377 unsigned long flags;
378 void __iomem *sensor_status_addr;
379 void __iomem *sensor_int_mask_addr;
380 void __iomem *sensor_upper_lower_addr;
381 u32 addr_offset = 0;
382
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700383 sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800384 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700385 TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800386 sensor_upper_lower_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700387 TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800388
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700389 for (i = 0; i < TSENS_MAX_SENSORS; i++) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800390 bool upper_thr = false, lower_thr = false;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700391 int int_mask, int_mask_val = 0, rc;
392
393 if (IS_ERR(tm->sensor[i].tzd))
394 continue;
395
396 rc = tsens2xxx_get_temp(&tm->sensor[i], &temp);
397 if (rc) {
398 pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
399 continue;
400 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800401
402 spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
403 addr_offset = tm->sensor[i].hw_id *
404 TSENS_TM_SN_ADDR_OFFSET;
405 status = readl_relaxed(sensor_status_addr + addr_offset);
406 threshold = readl_relaxed(sensor_upper_lower_addr +
407 addr_offset);
408 int_mask = readl_relaxed(sensor_int_mask_addr);
409
410 if ((status & TSENS_TM_SN_STATUS_UPPER_STATUS) &&
411 !(int_mask &
412 (1 << (tm->sensor[i].hw_id + 16)))) {
413 int_mask = readl_relaxed(sensor_int_mask_addr);
414 int_mask_val = TSENS_TM_UPPER_INT_SET(
415 tm->sensor[i].hw_id);
416 /* Mask the corresponding interrupt for the sensors */
417 writel_relaxed(int_mask | int_mask_val,
418 TSENS_TM_UPPER_LOWER_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700419 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800420 /* Clear the corresponding sensors interrupt */
421 writel_relaxed(int_mask_val,
422 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700423 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800424 writel_relaxed(0,
425 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700426 tm->tsens_tm_addr));
427 if (TSENS_TM_UPPER_THRESHOLD_VALUE(threshold) >
428 (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
429 pr_debug("Re-arm high threshold\n");
430 rc = tsens_tm_activate_trip_type(
431 &tm->sensor[i],
432 THERMAL_TRIP_CONFIGURABLE_HI,
433 THERMAL_TRIP_ACTIVATION_ENABLED);
434 if (rc)
435 pr_err("high rearm failed:%d\n", rc);
436 } else {
437 upper_thr = true;
438 tm->sensor[i].thr_state.
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800439 high_th_state = THERMAL_DEVICE_DISABLED;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700440 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800441 }
442
443 if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) &&
444 !(int_mask &
445 (1 << tm->sensor[i].hw_id))) {
446 int_mask = readl_relaxed(sensor_int_mask_addr);
447 int_mask_val = (1 << tm->sensor[i].hw_id);
448 /* Mask the corresponding interrupt for the sensors */
449 writel_relaxed(int_mask | int_mask_val,
450 TSENS_TM_UPPER_LOWER_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700451 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800452 /* Clear the corresponding sensors interrupt */
453 writel_relaxed(int_mask_val,
454 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700455 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800456 writel_relaxed(0,
457 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700458 tm->tsens_tm_addr));
459 if (TSENS_TM_LOWER_THRESHOLD_VALUE(threshold)
460 < (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
461 pr_debug("Re-arm low threshold\n");
462 rc = tsens_tm_activate_trip_type(
463 &tm->sensor[i],
464 THERMAL_TRIP_CONFIGURABLE_LOW,
465 THERMAL_TRIP_ACTIVATION_ENABLED);
466 if (rc)
467 pr_err("low rearm failed:%d\n", rc);
468 } else {
469 lower_thr = true;
470 tm->sensor[i].thr_state.
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800471 low_th_state = THERMAL_DEVICE_DISABLED;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700472 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800473 }
474 spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
475
476 if (upper_thr || lower_thr) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800477 /* Use id for multiple controllers */
478 pr_debug("sensor:%d trigger temp (%d degC)\n",
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700479 tm->sensor[i].hw_id, temp);
480 of_thermal_handle_trip(tm->sensor[i].tzd);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800481 }
482 }
483
484 /* Disable monitoring sensor trip threshold for triggered sensor */
485 mb();
486
487 if (tm->ops->dbg)
488 tm->ops->dbg(tm, 0, TSENS_DBG_LOG_INTERRUPT_TIMESTAMP, NULL);
489
490 return IRQ_HANDLED;
491}
492
493static int tsens2xxx_hw_init(struct tsens_device *tmdev)
494{
495 void __iomem *srot_addr;
496 void __iomem *sensor_int_mask_addr;
497 unsigned int srot_val;
498 int crit_mask;
499
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700500 srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800501 srot_val = readl_relaxed(srot_addr);
502 if (!(srot_val & TSENS_EN)) {
503 pr_err("TSENS device is not enabled\n");
504 return -ENODEV;
505 }
506
507 if (tmdev->ctrl_data->cycle_monitor) {
508 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700509 TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800510 crit_mask = readl_relaxed(sensor_int_mask_addr);
511 writel_relaxed(
512 crit_mask | tmdev->ctrl_data->cycle_compltn_monitor_val,
513 (TSENS_TM_CRITICAL_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700514 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800515 /*Update critical cycle monitoring*/
516 mb();
517 }
518 writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
519 TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700520 TSENS_TM_INT_EN(tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800521
522 spin_lock_init(&tmdev->tsens_crit_lock);
523 spin_lock_init(&tmdev->tsens_upp_low_lock);
524
525 return 0;
526}
527
528static const struct tsens_irqs tsens2xxx_irqs[] = {
529 { "tsens-upper-lower", tsens_tm_irq_thread},
530 { "tsens-critical", tsens_tm_critical_irq_thread},
531};
532
533static int tsens2xxx_register_interrupts(struct tsens_device *tmdev)
534{
535 struct platform_device *pdev;
536 int i, rc;
537
538 if (!tmdev)
539 return -EINVAL;
540
541 pdev = tmdev->pdev;
542
543 for (i = 0; i < ARRAY_SIZE(tsens2xxx_irqs); i++) {
544 int irq;
545
546 irq = platform_get_irq_byname(pdev, tsens2xxx_irqs[i].name);
547 if (irq < 0) {
548 dev_err(&pdev->dev, "failed to get irq %s\n",
549 tsens2xxx_irqs[i].name);
550 return irq;
551 }
552
553 rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
554 tsens2xxx_irqs[i].handler,
555 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
556 tsens2xxx_irqs[i].name, tmdev);
557 if (rc) {
558 dev_err(&pdev->dev, "failed to get irq %s\n",
559 tsens2xxx_irqs[i].name);
560 return rc;
561 }
562 enable_irq_wake(irq);
563 }
564
565 return 0;
566}
567
568static const struct tsens_ops ops_tsens2xxx = {
569 .hw_init = tsens2xxx_hw_init,
570 .get_temp = tsens2xxx_get_temp,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700571 .set_trips = tsens2xxx_set_trip_temp,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800572 .interrupts_reg = tsens2xxx_register_interrupts,
573 .dbg = tsens2xxx_dbg,
574};
575
576const struct tsens_data data_tsens2xxx = {
577 .cycle_monitor = false,
578 .cycle_compltn_monitor_val = 0,
579 .wd_bark = false,
580 .wd_bark_val = 0,
581 .ops = &ops_tsens2xxx,
582};
583
584const struct tsens_data data_tsens23xx = {
585 .cycle_monitor = true,
586 .cycle_compltn_monitor_val = 0,
587 .wd_bark = true,
588 .wd_bark_val = 0,
589 .ops = &ops_tsens2xxx,
590};
591
592const struct tsens_data data_tsens24xx = {
593 .cycle_monitor = true,
594 .cycle_compltn_monitor_val = 0,
595 .wd_bark = true,
596 .wd_bark_val = 1,
597 .ops = &ops_tsens2xxx,
598};