blob: 50c847febf73d9dbded5830b1f0440f4f4aab161 [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 Mohanadoss64a5da32017-05-09 11:09:51 -070060#define TSENS_DEBUG_WDOG_TRIGGER_COUNT 5
61#define TSENS_TM_WATCHDOG_LOG(n) ((n) + 0x13c)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080062
63#define TSENS_EN BIT(0)
Siddartha Mohanadossf86413d2017-07-18 13:44:31 -070064#define TSENS_CTRL_SENSOR_EN_MASK(n) ((n >> 3) & 0xffff)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080065
66static void msm_tsens_convert_temp(int last_temp, int *temp)
67{
68 int code_mask = ~TSENS_TM_CODE_BIT_MASK;
69
70 if (last_temp & TSENS_TM_CODE_SIGN_BIT) {
71 /* Sign extension for negative value */
72 last_temp |= code_mask;
73 }
74
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070075 *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080076}
77
78static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
79{
80 struct tsens_device *tmdev = NULL;
81 unsigned int code;
82 void __iomem *sensor_addr;
83 int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
84
85 if (!sensor)
86 return -EINVAL;
87
88 tmdev = sensor->tmdev;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -070089 sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080090
91 code = readl_relaxed_no_log(sensor_addr +
92 (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
93 last_temp = code & TSENS_TM_SN_LAST_TEMP_MASK;
94
95 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
96 msm_tsens_convert_temp(last_temp, temp);
Rama Krishna Phani A6ad66332017-10-25 21:20:04 +053097 goto dbg;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -080098 }
99
100 code = readl_relaxed_no_log(sensor_addr +
101 (sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
102 last_temp2 = code & TSENS_TM_SN_LAST_TEMP_MASK;
103 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
104 last_temp = last_temp2;
105 msm_tsens_convert_temp(last_temp, temp);
Rama Krishna Phani A6ad66332017-10-25 21:20:04 +0530106 goto dbg;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800107 }
108
109 code = readl_relaxed_no_log(sensor_addr +
110 (sensor->hw_id <<
111 TSENS_STATUS_ADDR_OFFSET));
112 last_temp3 = code & TSENS_TM_SN_LAST_TEMP_MASK;
113 if (code & TSENS_TM_SN_STATUS_VALID_BIT) {
114 last_temp = last_temp3;
115 msm_tsens_convert_temp(last_temp, temp);
Rama Krishna Phani A6ad66332017-10-25 21:20:04 +0530116 goto dbg;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800117 }
118
119 if (last_temp == last_temp2)
120 last_temp = last_temp2;
121 else if (last_temp2 == last_temp3)
122 last_temp = last_temp3;
123
124 msm_tsens_convert_temp(last_temp, temp);
125
Rama Krishna Phani A6ad66332017-10-25 21:20:04 +0530126dbg:
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800127 if (tmdev->ops->dbg)
128 tmdev->ops->dbg(tmdev, (u32) sensor->hw_id,
129 TSENS_DBG_LOG_TEMP_READS, temp);
130
131 return 0;
132}
133
134static int tsens_tm_activate_trip_type(struct tsens_sensor *tm_sensor,
135 int trip, enum thermal_trip_activation_mode mode)
136{
137 struct tsens_device *tmdev = NULL;
138 unsigned int reg_cntl, mask;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800139 int rc = 0;
140
141 /* clear the interrupt and unmask */
142 if (!tm_sensor || trip < 0)
143 return -EINVAL;
144
145 tmdev = tm_sensor->tmdev;
146 if (!tmdev)
147 return -EINVAL;
148
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700149
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800150 mask = (tm_sensor->hw_id);
151 switch (trip) {
152 case THERMAL_TRIP_CRITICAL:
153 tmdev->sensor[tm_sensor->hw_id].
154 thr_state.crit_th_state = mode;
155 reg_cntl = readl_relaxed(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 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
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 else
162 writel_relaxed(reg_cntl & ~(1 << mask),
163 (TSENS_TM_CRITICAL_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700164 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800165 break;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700166 case THERMAL_TRIP_CONFIGURABLE_HI:
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800167 tmdev->sensor[tm_sensor->hw_id].
168 thr_state.high_th_state = mode;
169 reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700170 (tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800171 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
172 writel_relaxed(reg_cntl |
173 (TSENS_TM_UPPER_INT_SET(mask)),
174 (TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700175 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800176 else
177 writel_relaxed(reg_cntl &
178 ~(TSENS_TM_UPPER_INT_SET(mask)),
179 (TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700180 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800181 break;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700182 case THERMAL_TRIP_CONFIGURABLE_LOW:
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800183 tmdev->sensor[tm_sensor->hw_id].
184 thr_state.low_th_state = mode;
185 reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700186 (tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800187 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
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 else
192 writel_relaxed(reg_cntl & ~(1 << mask),
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700193 (TSENS_TM_UPPER_LOWER_INT_MASK
194 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800195 break;
196 default:
197 rc = -EINVAL;
198 }
199
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800200 /* Activate and enable the respective trip threshold setting */
201 mb();
202
203 return rc;
204}
205
206static int tsens2xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700207 int low_temp, int high_temp)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800208{
209 unsigned int reg_cntl;
210 unsigned long flags;
211 struct tsens_device *tmdev = NULL;
212 int rc = 0;
213
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700214 if (!tm_sensor)
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800215 return -EINVAL;
216
217 tmdev = tm_sensor->tmdev;
218 if (!tmdev)
219 return -EINVAL;
220
221 spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700222
223 if (high_temp != INT_MAX) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800224 tmdev->sensor[tm_sensor->hw_id].
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700225 thr_state.high_temp = high_temp;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800226 reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700227 (tmdev->tsens_tm_addr)) +
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800228 (tm_sensor->hw_id *
229 TSENS_TM_SN_ADDR_OFFSET));
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700230 high_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
231 high_temp = TSENS_TM_UPPER_THRESHOLD_SET(high_temp);
232 high_temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800233 reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700234 writel_relaxed(reg_cntl | high_temp,
235 (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
236 (tmdev->tsens_tm_addr) +
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800237 (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800238 }
239
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700240 if (low_temp != INT_MIN) {
241 tmdev->sensor[tm_sensor->hw_id].
242 thr_state.low_temp = low_temp;
243 reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
244 (tmdev->tsens_tm_addr)) +
245 (tm_sensor->hw_id *
246 TSENS_TM_SN_ADDR_OFFSET));
247 low_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
248 low_temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
249 reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
250 writel_relaxed(reg_cntl | low_temp,
251 (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
252 (tmdev->tsens_tm_addr) +
253 (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
254 }
255
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800256 /* Set trip temperature thresholds */
257 mb();
258
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700259 if (high_temp != INT_MAX) {
260 rc = tsens_tm_activate_trip_type(tm_sensor,
261 THERMAL_TRIP_CONFIGURABLE_HI,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800262 THERMAL_TRIP_ACTIVATION_ENABLED);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700263 if (rc) {
Siddartha Mohanadossf10a5a32017-04-19 09:31:39 -0700264 pr_err("trip high enable error :%d\n", rc);
265 goto fail;
266 }
267 } else {
268 rc = tsens_tm_activate_trip_type(tm_sensor,
269 THERMAL_TRIP_CONFIGURABLE_HI,
270 THERMAL_TRIP_ACTIVATION_DISABLED);
271 if (rc) {
272 pr_err("trip high disable error :%d\n", rc);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700273 goto fail;
274 }
275 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800276
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700277 if (low_temp != INT_MIN) {
278 rc = tsens_tm_activate_trip_type(tm_sensor,
279 THERMAL_TRIP_CONFIGURABLE_LOW,
280 THERMAL_TRIP_ACTIVATION_ENABLED);
281 if (rc) {
Siddartha Mohanadossf10a5a32017-04-19 09:31:39 -0700282 pr_err("trip low enable activation error :%d\n", rc);
283 goto fail;
284 }
285 } else {
286 rc = tsens_tm_activate_trip_type(tm_sensor,
287 THERMAL_TRIP_CONFIGURABLE_LOW,
288 THERMAL_TRIP_ACTIVATION_DISABLED);
289 if (rc) {
290 pr_err("trip low disable error :%d\n", rc);
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700291 goto fail;
292 }
293 }
294
295fail:
296 spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800297 return rc;
298}
299
300static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data)
301{
302 struct tsens_device *tm = data;
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700303 unsigned int i, status, wd_log, wd_mask;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800304 unsigned long flags;
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700305 void __iomem *sensor_status_addr, *sensor_int_mask_addr;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800306 void __iomem *sensor_critical_addr;
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700307 void __iomem *wd_critical_addr, *wd_log_addr;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800308
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700309 sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800310 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700311 TSENS_TM_CRITICAL_INT_MASK(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800312 sensor_critical_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700313 TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800314 wd_critical_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700315 TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700316 wd_log_addr = TSENS_TM_WATCHDOG_LOG(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800317
318 if (tm->ctrl_data->wd_bark) {
319 wd_mask = readl_relaxed(wd_critical_addr);
320 if (wd_mask & TSENS_TM_CRITICAL_WD_BARK) {
321 /*
322 * Clear watchdog interrupt and
323 * increment global wd count
324 */
325 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 writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
329 (TSENS_TM_CRITICAL_INT_CLEAR
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700330 (tm->tsens_tm_addr)));
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700331 wd_log = readl_relaxed(wd_log_addr);
332 if (wd_log >= TSENS_DEBUG_WDOG_TRIGGER_COUNT) {
333 pr_err("Watchdog count:%d\n", wd_log);
334 if (tm->ops->dbg)
335 tm->ops->dbg(tm, 0,
336 TSENS_DBG_LOG_BUS_ID_DATA, NULL);
337 BUG();
338 }
339
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800340 return IRQ_HANDLED;
341 }
342 }
343
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700344 for (i = 0; i < TSENS_MAX_SENSORS; i++) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800345 int int_mask, int_mask_val;
346 u32 addr_offset;
347
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700348 if (IS_ERR(tm->sensor[i].tzd))
349 continue;
350
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800351 spin_lock_irqsave(&tm->tsens_crit_lock, flags);
352 addr_offset = tm->sensor[i].hw_id *
353 TSENS_TM_SN_ADDR_OFFSET;
354 status = readl_relaxed(sensor_status_addr + addr_offset);
355 int_mask = readl_relaxed(sensor_int_mask_addr);
356
357 if ((status & TSENS_TM_SN_STATUS_CRITICAL_STATUS) &&
358 !(int_mask & (1 << tm->sensor[i].hw_id))) {
359 int_mask = readl_relaxed(sensor_int_mask_addr);
360 int_mask_val = (1 << tm->sensor[i].hw_id);
361 /* Mask the corresponding interrupt for the sensors */
362 writel_relaxed(int_mask | int_mask_val,
363 TSENS_TM_CRITICAL_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700364 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800365 /* Clear the corresponding sensors interrupt */
366 writel_relaxed(int_mask_val,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700367 TSENS_TM_CRITICAL_INT_CLEAR
368 (tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800369 writel_relaxed(0,
370 TSENS_TM_CRITICAL_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700371 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800372 tm->sensor[i].thr_state.
373 crit_th_state = THERMAL_DEVICE_DISABLED;
374 }
375 spin_unlock_irqrestore(&tm->tsens_crit_lock, flags);
376 }
377
378 /* Mask critical interrupt */
379 mb();
380
381 return IRQ_HANDLED;
382}
383
384static irqreturn_t tsens_tm_irq_thread(int irq, void *data)
385{
386 struct tsens_device *tm = data;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700387 unsigned int i, status, threshold, temp;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800388 unsigned long flags;
389 void __iomem *sensor_status_addr;
390 void __iomem *sensor_int_mask_addr;
391 void __iomem *sensor_upper_lower_addr;
392 u32 addr_offset = 0;
393
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700394 sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800395 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700396 TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800397 sensor_upper_lower_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700398 TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800399
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700400 for (i = 0; i < TSENS_MAX_SENSORS; i++) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800401 bool upper_thr = false, lower_thr = false;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700402 int int_mask, int_mask_val = 0, rc;
403
404 if (IS_ERR(tm->sensor[i].tzd))
405 continue;
406
407 rc = tsens2xxx_get_temp(&tm->sensor[i], &temp);
408 if (rc) {
409 pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
410 continue;
411 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800412
413 spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
414 addr_offset = tm->sensor[i].hw_id *
415 TSENS_TM_SN_ADDR_OFFSET;
416 status = readl_relaxed(sensor_status_addr + addr_offset);
417 threshold = readl_relaxed(sensor_upper_lower_addr +
418 addr_offset);
419 int_mask = readl_relaxed(sensor_int_mask_addr);
420
421 if ((status & TSENS_TM_SN_STATUS_UPPER_STATUS) &&
422 !(int_mask &
423 (1 << (tm->sensor[i].hw_id + 16)))) {
424 int_mask = readl_relaxed(sensor_int_mask_addr);
425 int_mask_val = TSENS_TM_UPPER_INT_SET(
426 tm->sensor[i].hw_id);
427 /* Mask the corresponding interrupt for the sensors */
428 writel_relaxed(int_mask | int_mask_val,
429 TSENS_TM_UPPER_LOWER_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700430 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800431 /* Clear the corresponding sensors interrupt */
432 writel_relaxed(int_mask_val,
433 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700434 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800435 writel_relaxed(0,
436 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700437 tm->tsens_tm_addr));
438 if (TSENS_TM_UPPER_THRESHOLD_VALUE(threshold) >
439 (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
440 pr_debug("Re-arm high threshold\n");
441 rc = tsens_tm_activate_trip_type(
442 &tm->sensor[i],
443 THERMAL_TRIP_CONFIGURABLE_HI,
444 THERMAL_TRIP_ACTIVATION_ENABLED);
445 if (rc)
446 pr_err("high rearm failed:%d\n", rc);
447 } else {
448 upper_thr = true;
449 tm->sensor[i].thr_state.
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800450 high_th_state = THERMAL_DEVICE_DISABLED;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700451 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800452 }
453
454 if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) &&
455 !(int_mask &
456 (1 << tm->sensor[i].hw_id))) {
457 int_mask = readl_relaxed(sensor_int_mask_addr);
458 int_mask_val = (1 << tm->sensor[i].hw_id);
459 /* Mask the corresponding interrupt for the sensors */
460 writel_relaxed(int_mask | int_mask_val,
461 TSENS_TM_UPPER_LOWER_INT_MASK(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700462 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800463 /* Clear the corresponding sensors interrupt */
464 writel_relaxed(int_mask_val,
465 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700466 tm->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800467 writel_relaxed(0,
468 TSENS_TM_UPPER_LOWER_INT_CLEAR(
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700469 tm->tsens_tm_addr));
470 if (TSENS_TM_LOWER_THRESHOLD_VALUE(threshold)
471 < (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
472 pr_debug("Re-arm low threshold\n");
473 rc = tsens_tm_activate_trip_type(
474 &tm->sensor[i],
475 THERMAL_TRIP_CONFIGURABLE_LOW,
476 THERMAL_TRIP_ACTIVATION_ENABLED);
477 if (rc)
478 pr_err("low rearm failed:%d\n", rc);
479 } else {
480 lower_thr = true;
481 tm->sensor[i].thr_state.
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800482 low_th_state = THERMAL_DEVICE_DISABLED;
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700483 }
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800484 }
485 spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
486
487 if (upper_thr || lower_thr) {
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800488 /* Use id for multiple controllers */
489 pr_debug("sensor:%d trigger temp (%d degC)\n",
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700490 tm->sensor[i].hw_id, temp);
491 of_thermal_handle_trip(tm->sensor[i].tzd);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800492 }
493 }
494
495 /* Disable monitoring sensor trip threshold for triggered sensor */
496 mb();
497
498 if (tm->ops->dbg)
499 tm->ops->dbg(tm, 0, TSENS_DBG_LOG_INTERRUPT_TIMESTAMP, NULL);
500
501 return IRQ_HANDLED;
502}
503
Siddartha Mohanadossf86413d2017-07-18 13:44:31 -0700504static int tsens2xxx_hw_sensor_en(struct tsens_device *tmdev,
505 u32 sensor_id)
506{
507 void __iomem *srot_addr;
508 unsigned int srot_val, sensor_en;
509
510 srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
511 srot_val = readl_relaxed(srot_addr);
512 srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
513
514 sensor_en = ((1 << sensor_id) & srot_val);
515
516 return sensor_en;
517}
518
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800519static int tsens2xxx_hw_init(struct tsens_device *tmdev)
520{
521 void __iomem *srot_addr;
522 void __iomem *sensor_int_mask_addr;
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700523 unsigned int srot_val, crit_mask, crit_val;
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800524
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700525 srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800526 srot_val = readl_relaxed(srot_addr);
527 if (!(srot_val & TSENS_EN)) {
528 pr_err("TSENS device is not enabled\n");
529 return -ENODEV;
530 }
531
532 if (tmdev->ctrl_data->cycle_monitor) {
533 sensor_int_mask_addr =
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700534 TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800535 crit_mask = readl_relaxed(sensor_int_mask_addr);
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700536 crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR;
537 if (tmdev->ctrl_data->cycle_compltn_monitor_mask)
538 writel_relaxed((crit_mask | crit_val),
539 (TSENS_TM_CRITICAL_INT_MASK
540 (tmdev->tsens_tm_addr)));
541 else
542 writel_relaxed((crit_mask & ~crit_val),
543 (TSENS_TM_CRITICAL_INT_MASK
544 (tmdev->tsens_tm_addr)));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800545 /*Update critical cycle monitoring*/
546 mb();
547 }
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700548
549 if (tmdev->ctrl_data->wd_bark) {
550 sensor_int_mask_addr =
551 TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
552 crit_mask = readl_relaxed(sensor_int_mask_addr);
553 crit_val = TSENS_TM_CRITICAL_WD_BARK;
554 if (tmdev->ctrl_data->wd_bark_mask)
555 writel_relaxed((crit_mask | crit_val),
556 (TSENS_TM_CRITICAL_INT_MASK
557 (tmdev->tsens_tm_addr)));
558 else
559 writel_relaxed((crit_mask & ~crit_val),
560 (TSENS_TM_CRITICAL_INT_MASK
561 (tmdev->tsens_tm_addr)));
562 /*Update watchdog monitoring*/
563 mb();
564 }
565
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800566 writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
567 TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700568 TSENS_TM_INT_EN(tmdev->tsens_tm_addr));
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800569
570 spin_lock_init(&tmdev->tsens_crit_lock);
571 spin_lock_init(&tmdev->tsens_upp_low_lock);
572
Ashok Jammigumpulaa1b7ec12017-11-23 15:37:44 +0530573 if (tmdev->ctrl_data->mtc) {
574 if (tmdev->ops->dbg)
575 tmdev->ops->dbg(tmdev, 0, TSENS_DBG_MTC_DATA, NULL);
576 }
577
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800578 return 0;
579}
580
581static const struct tsens_irqs tsens2xxx_irqs[] = {
582 { "tsens-upper-lower", tsens_tm_irq_thread},
583 { "tsens-critical", tsens_tm_critical_irq_thread},
584};
585
586static int tsens2xxx_register_interrupts(struct tsens_device *tmdev)
587{
588 struct platform_device *pdev;
589 int i, rc;
590
591 if (!tmdev)
592 return -EINVAL;
593
594 pdev = tmdev->pdev;
595
596 for (i = 0; i < ARRAY_SIZE(tsens2xxx_irqs); i++) {
597 int irq;
598
599 irq = platform_get_irq_byname(pdev, tsens2xxx_irqs[i].name);
600 if (irq < 0) {
601 dev_err(&pdev->dev, "failed to get irq %s\n",
602 tsens2xxx_irqs[i].name);
603 return irq;
604 }
605
606 rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
607 tsens2xxx_irqs[i].handler,
608 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
609 tsens2xxx_irqs[i].name, tmdev);
610 if (rc) {
611 dev_err(&pdev->dev, "failed to get irq %s\n",
612 tsens2xxx_irqs[i].name);
613 return rc;
614 }
615 enable_irq_wake(irq);
616 }
617
618 return 0;
619}
620
621static const struct tsens_ops ops_tsens2xxx = {
622 .hw_init = tsens2xxx_hw_init,
623 .get_temp = tsens2xxx_get_temp,
Siddartha Mohanadoss07b10612017-04-07 14:53:45 -0700624 .set_trips = tsens2xxx_set_trip_temp,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800625 .interrupts_reg = tsens2xxx_register_interrupts,
626 .dbg = tsens2xxx_dbg,
Siddartha Mohanadossf86413d2017-07-18 13:44:31 -0700627 .sensor_en = tsens2xxx_hw_sensor_en,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800628};
629
630const struct tsens_data data_tsens2xxx = {
631 .cycle_monitor = false,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700632 .cycle_compltn_monitor_mask = 1,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800633 .wd_bark = false,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700634 .wd_bark_mask = 1,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800635 .ops = &ops_tsens2xxx,
Ashok Jammigumpulaa1b7ec12017-11-23 15:37:44 +0530636 .mtc = true,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800637};
638
639const struct tsens_data data_tsens23xx = {
640 .cycle_monitor = true,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700641 .cycle_compltn_monitor_mask = 1,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800642 .wd_bark = true,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700643 .wd_bark_mask = 1,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800644 .ops = &ops_tsens2xxx,
Ashok Jammigumpulaa1b7ec12017-11-23 15:37:44 +0530645 .mtc = false,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800646};
647
648const struct tsens_data data_tsens24xx = {
649 .cycle_monitor = true,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700650 .cycle_compltn_monitor_mask = 1,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800651 .wd_bark = true,
Siddartha Mohanadoss64a5da32017-05-09 11:09:51 -0700652 /* Enable Watchdog monitoring by unmasking */
653 .wd_bark_mask = 0,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800654 .ops = &ops_tsens2xxx,
Ashok Jammigumpulaa1b7ec12017-11-23 15:37:44 +0530655 .mtc = false,
Siddartha Mohanadoss41b4cd92017-02-21 14:34:23 -0800656};