1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2019, 2020, Linaro Ltd. |
5 | */ |
6 | |
7 | #include <linux/debugfs.h> |
8 | #include <linux/err.h> |
9 | #include <linux/io.h> |
10 | #include <linux/module.h> |
11 | #include <linux/nvmem-consumer.h> |
12 | #include <linux/of.h> |
13 | #include <linux/of_address.h> |
14 | #include <linux/of_platform.h> |
15 | #include <linux/mfd/syscon.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pm.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/thermal.h> |
21 | #include "../thermal_hwmon.h" |
22 | #include "tsens.h" |
23 | |
24 | /** |
25 | * struct tsens_irq_data - IRQ status and temperature violations |
26 | * @up_viol: upper threshold violated |
27 | * @up_thresh: upper threshold temperature value |
28 | * @up_irq_mask: mask register for upper threshold irqs |
29 | * @up_irq_clear: clear register for uppper threshold irqs |
30 | * @low_viol: lower threshold violated |
31 | * @low_thresh: lower threshold temperature value |
32 | * @low_irq_mask: mask register for lower threshold irqs |
33 | * @low_irq_clear: clear register for lower threshold irqs |
34 | * @crit_viol: critical threshold violated |
35 | * @crit_thresh: critical threshold temperature value |
36 | * @crit_irq_mask: mask register for critical threshold irqs |
37 | * @crit_irq_clear: clear register for critical threshold irqs |
38 | * |
39 | * Structure containing data about temperature threshold settings and |
40 | * irq status if they were violated. |
41 | */ |
42 | struct tsens_irq_data { |
43 | u32 up_viol; |
44 | int up_thresh; |
45 | u32 up_irq_mask; |
46 | u32 up_irq_clear; |
47 | u32 low_viol; |
48 | int low_thresh; |
49 | u32 low_irq_mask; |
50 | u32 low_irq_clear; |
51 | u32 crit_viol; |
52 | u32 crit_thresh; |
53 | u32 crit_irq_mask; |
54 | u32 crit_irq_clear; |
55 | }; |
56 | |
57 | char *qfprom_read(struct device *dev, const char *cname) |
58 | { |
59 | struct nvmem_cell *cell; |
60 | ssize_t data; |
61 | char *ret; |
62 | |
63 | cell = nvmem_cell_get(dev, id: cname); |
64 | if (IS_ERR(ptr: cell)) |
65 | return ERR_CAST(ptr: cell); |
66 | |
67 | ret = nvmem_cell_read(cell, len: &data); |
68 | nvmem_cell_put(cell); |
69 | |
70 | return ret; |
71 | } |
72 | |
73 | int tsens_read_calibration(struct tsens_priv *priv, int shift, u32 *p1, u32 *p2, bool backup) |
74 | { |
75 | u32 mode; |
76 | u32 base1, base2; |
77 | char name[] = "sXX_pY_backup" ; /* s10_p1_backup */ |
78 | int i, ret; |
79 | |
80 | if (priv->num_sensors > MAX_SENSORS) |
81 | return -EINVAL; |
82 | |
83 | ret = snprintf(buf: name, size: sizeof(name), fmt: "mode%s" , backup ? "_backup" : "" ); |
84 | if (ret < 0) |
85 | return ret; |
86 | |
87 | ret = nvmem_cell_read_variable_le_u32(dev: priv->dev, cell_id: name, val: &mode); |
88 | if (ret == -ENOENT) |
89 | dev_warn(priv->dev, "Please migrate to separate nvmem cells for calibration data\n" ); |
90 | if (ret < 0) |
91 | return ret; |
92 | |
93 | dev_dbg(priv->dev, "calibration mode is %d\n" , mode); |
94 | |
95 | ret = snprintf(buf: name, size: sizeof(name), fmt: "base1%s" , backup ? "_backup" : "" ); |
96 | if (ret < 0) |
97 | return ret; |
98 | |
99 | ret = nvmem_cell_read_variable_le_u32(dev: priv->dev, cell_id: name, val: &base1); |
100 | if (ret < 0) |
101 | return ret; |
102 | |
103 | ret = snprintf(buf: name, size: sizeof(name), fmt: "base2%s" , backup ? "_backup" : "" ); |
104 | if (ret < 0) |
105 | return ret; |
106 | |
107 | ret = nvmem_cell_read_variable_le_u32(dev: priv->dev, cell_id: name, val: &base2); |
108 | if (ret < 0) |
109 | return ret; |
110 | |
111 | for (i = 0; i < priv->num_sensors; i++) { |
112 | ret = snprintf(buf: name, size: sizeof(name), fmt: "s%d_p1%s" , priv->sensor[i].hw_id, |
113 | backup ? "_backup" : "" ); |
114 | if (ret < 0) |
115 | return ret; |
116 | |
117 | ret = nvmem_cell_read_variable_le_u32(dev: priv->dev, cell_id: name, val: &p1[i]); |
118 | if (ret) |
119 | return ret; |
120 | |
121 | ret = snprintf(buf: name, size: sizeof(name), fmt: "s%d_p2%s" , priv->sensor[i].hw_id, |
122 | backup ? "_backup" : "" ); |
123 | if (ret < 0) |
124 | return ret; |
125 | |
126 | ret = nvmem_cell_read_variable_le_u32(dev: priv->dev, cell_id: name, val: &p2[i]); |
127 | if (ret) |
128 | return ret; |
129 | } |
130 | |
131 | switch (mode) { |
132 | case ONE_PT_CALIB: |
133 | for (i = 0; i < priv->num_sensors; i++) |
134 | p1[i] = p1[i] + (base1 << shift); |
135 | break; |
136 | case TWO_PT_CALIB: |
137 | case TWO_PT_CALIB_NO_OFFSET: |
138 | for (i = 0; i < priv->num_sensors; i++) |
139 | p2[i] = (p2[i] + base2) << shift; |
140 | fallthrough; |
141 | case ONE_PT_CALIB2: |
142 | case ONE_PT_CALIB2_NO_OFFSET: |
143 | for (i = 0; i < priv->num_sensors; i++) |
144 | p1[i] = (p1[i] + base1) << shift; |
145 | break; |
146 | default: |
147 | dev_dbg(priv->dev, "calibrationless mode\n" ); |
148 | for (i = 0; i < priv->num_sensors; i++) { |
149 | p1[i] = 500; |
150 | p2[i] = 780; |
151 | } |
152 | } |
153 | |
154 | /* Apply calibration offset workaround except for _NO_OFFSET modes */ |
155 | switch (mode) { |
156 | case TWO_PT_CALIB: |
157 | for (i = 0; i < priv->num_sensors; i++) |
158 | p2[i] += priv->sensor[i].p2_calib_offset; |
159 | fallthrough; |
160 | case ONE_PT_CALIB2: |
161 | for (i = 0; i < priv->num_sensors; i++) |
162 | p1[i] += priv->sensor[i].p1_calib_offset; |
163 | break; |
164 | } |
165 | |
166 | return mode; |
167 | } |
168 | |
169 | int tsens_calibrate_nvmem(struct tsens_priv *priv, int shift) |
170 | { |
171 | u32 p1[MAX_SENSORS], p2[MAX_SENSORS]; |
172 | int mode; |
173 | |
174 | mode = tsens_read_calibration(priv, shift, p1, p2, backup: false); |
175 | if (mode < 0) |
176 | return mode; |
177 | |
178 | compute_intercept_slope(priv, pt1: p1, pt2: p2, mode); |
179 | |
180 | return 0; |
181 | } |
182 | |
183 | int tsens_calibrate_common(struct tsens_priv *priv) |
184 | { |
185 | return tsens_calibrate_nvmem(priv, shift: 2); |
186 | } |
187 | |
188 | static u32 tsens_read_cell(const struct tsens_single_value *cell, u8 len, u32 *data0, u32 *data1) |
189 | { |
190 | u32 val; |
191 | u32 *data = cell->blob ? data1 : data0; |
192 | |
193 | if (cell->shift + len <= 32) { |
194 | val = data[cell->idx] >> cell->shift; |
195 | } else { |
196 | u8 part = 32 - cell->shift; |
197 | |
198 | val = data[cell->idx] >> cell->shift; |
199 | val |= data[cell->idx + 1] << part; |
200 | } |
201 | |
202 | return val & ((1 << len) - 1); |
203 | } |
204 | |
205 | int tsens_read_calibration_legacy(struct tsens_priv *priv, |
206 | const struct tsens_legacy_calibration_format *format, |
207 | u32 *p1, u32 *p2, |
208 | u32 *cdata0, u32 *cdata1) |
209 | { |
210 | u32 mode, invalid; |
211 | u32 base1, base2; |
212 | int i; |
213 | |
214 | mode = tsens_read_cell(cell: &format->mode, len: 2, data0: cdata0, data1: cdata1); |
215 | invalid = tsens_read_cell(cell: &format->invalid, len: 1, data0: cdata0, data1: cdata1); |
216 | if (invalid) |
217 | mode = NO_PT_CALIB; |
218 | dev_dbg(priv->dev, "calibration mode is %d\n" , mode); |
219 | |
220 | base1 = tsens_read_cell(cell: &format->base[0], len: format->base_len, data0: cdata0, data1: cdata1); |
221 | base2 = tsens_read_cell(cell: &format->base[1], len: format->base_len, data0: cdata0, data1: cdata1); |
222 | |
223 | for (i = 0; i < priv->num_sensors; i++) { |
224 | p1[i] = tsens_read_cell(cell: &format->sp[i][0], len: format->sp_len, data0: cdata0, data1: cdata1); |
225 | p2[i] = tsens_read_cell(cell: &format->sp[i][1], len: format->sp_len, data0: cdata0, data1: cdata1); |
226 | } |
227 | |
228 | switch (mode) { |
229 | case ONE_PT_CALIB: |
230 | for (i = 0; i < priv->num_sensors; i++) |
231 | p1[i] = p1[i] + (base1 << format->base_shift); |
232 | break; |
233 | case TWO_PT_CALIB: |
234 | for (i = 0; i < priv->num_sensors; i++) |
235 | p2[i] = (p2[i] + base2) << format->base_shift; |
236 | fallthrough; |
237 | case ONE_PT_CALIB2: |
238 | for (i = 0; i < priv->num_sensors; i++) |
239 | p1[i] = (p1[i] + base1) << format->base_shift; |
240 | break; |
241 | default: |
242 | dev_dbg(priv->dev, "calibrationless mode\n" ); |
243 | for (i = 0; i < priv->num_sensors; i++) { |
244 | p1[i] = 500; |
245 | p2[i] = 780; |
246 | } |
247 | } |
248 | |
249 | return mode; |
250 | } |
251 | |
252 | /* |
253 | * Use this function on devices where slope and offset calculations |
254 | * depend on calibration data read from qfprom. On others the slope |
255 | * and offset values are derived from tz->tzp->slope and tz->tzp->offset |
256 | * resp. |
257 | */ |
258 | void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, |
259 | u32 *p2, u32 mode) |
260 | { |
261 | int i; |
262 | int num, den; |
263 | |
264 | for (i = 0; i < priv->num_sensors; i++) { |
265 | dev_dbg(priv->dev, |
266 | "%s: sensor%d - data_point1:%#x data_point2:%#x\n" , |
267 | __func__, i, p1[i], p2[i]); |
268 | |
269 | if (!priv->sensor[i].slope) |
270 | priv->sensor[i].slope = SLOPE_DEFAULT; |
271 | if (mode == TWO_PT_CALIB || mode == TWO_PT_CALIB_NO_OFFSET) { |
272 | /* |
273 | * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ |
274 | * temp_120_degc - temp_30_degc (x2 - x1) |
275 | */ |
276 | num = p2[i] - p1[i]; |
277 | num *= SLOPE_FACTOR; |
278 | den = CAL_DEGC_PT2 - CAL_DEGC_PT1; |
279 | priv->sensor[i].slope = num / den; |
280 | } |
281 | |
282 | priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - |
283 | (CAL_DEGC_PT1 * |
284 | priv->sensor[i].slope); |
285 | dev_dbg(priv->dev, "%s: offset:%d\n" , __func__, |
286 | priv->sensor[i].offset); |
287 | } |
288 | } |
289 | |
290 | static inline u32 degc_to_code(int degc, const struct tsens_sensor *s) |
291 | { |
292 | u64 code = div_u64(dividend: ((u64)degc * s->slope + s->offset), SLOPE_FACTOR); |
293 | |
294 | pr_debug("%s: raw_code: 0x%llx, degc:%d\n" , __func__, code, degc); |
295 | return clamp_val(code, THRESHOLD_MIN_ADC_CODE, THRESHOLD_MAX_ADC_CODE); |
296 | } |
297 | |
298 | static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) |
299 | { |
300 | int degc, num, den; |
301 | |
302 | num = (adc_code * SLOPE_FACTOR) - s->offset; |
303 | den = s->slope; |
304 | |
305 | if (num > 0) |
306 | degc = num + (den / 2); |
307 | else if (num < 0) |
308 | degc = num - (den / 2); |
309 | else |
310 | degc = num; |
311 | |
312 | degc /= den; |
313 | |
314 | return degc; |
315 | } |
316 | |
317 | /** |
318 | * tsens_hw_to_mC - Return sign-extended temperature in mCelsius. |
319 | * @s: Pointer to sensor struct |
320 | * @field: Index into regmap_field array pointing to temperature data |
321 | * |
322 | * This function handles temperature returned in ADC code or deciCelsius |
323 | * depending on IP version. |
324 | * |
325 | * Return: Temperature in milliCelsius on success, a negative errno will |
326 | * be returned in error cases |
327 | */ |
328 | static int tsens_hw_to_mC(const struct tsens_sensor *s, int field) |
329 | { |
330 | struct tsens_priv *priv = s->priv; |
331 | u32 resolution; |
332 | u32 temp = 0; |
333 | int ret; |
334 | |
335 | resolution = priv->fields[LAST_TEMP_0].msb - |
336 | priv->fields[LAST_TEMP_0].lsb; |
337 | |
338 | ret = regmap_field_read(field: priv->rf[field], val: &temp); |
339 | if (ret) |
340 | return ret; |
341 | |
342 | /* Convert temperature from ADC code to milliCelsius */ |
343 | if (priv->feat->adc) |
344 | return code_to_degc(adc_code: temp, s) * 1000; |
345 | |
346 | /* deciCelsius -> milliCelsius along with sign extension */ |
347 | return sign_extend32(value: temp, index: resolution) * 100; |
348 | } |
349 | |
350 | /** |
351 | * tsens_mC_to_hw - Convert temperature to hardware register value |
352 | * @s: Pointer to sensor struct |
353 | * @temp: temperature in milliCelsius to be programmed to hardware |
354 | * |
355 | * This function outputs the value to be written to hardware in ADC code |
356 | * or deciCelsius depending on IP version. |
357 | * |
358 | * Return: ADC code or temperature in deciCelsius. |
359 | */ |
360 | static int tsens_mC_to_hw(const struct tsens_sensor *s, int temp) |
361 | { |
362 | struct tsens_priv *priv = s->priv; |
363 | |
364 | /* milliC to adc code */ |
365 | if (priv->feat->adc) |
366 | return degc_to_code(degc: temp / 1000, s); |
367 | |
368 | /* milliC to deciC */ |
369 | return temp / 100; |
370 | } |
371 | |
372 | static inline enum tsens_ver tsens_version(struct tsens_priv *priv) |
373 | { |
374 | return priv->feat->ver_major; |
375 | } |
376 | |
377 | static void tsens_set_interrupt_v1(struct tsens_priv *priv, u32 hw_id, |
378 | enum tsens_irq_type irq_type, bool enable) |
379 | { |
380 | u32 index = 0; |
381 | |
382 | switch (irq_type) { |
383 | case UPPER: |
384 | index = UP_INT_CLEAR_0 + hw_id; |
385 | break; |
386 | case LOWER: |
387 | index = LOW_INT_CLEAR_0 + hw_id; |
388 | break; |
389 | case CRITICAL: |
390 | /* No critical interrupts before v2 */ |
391 | return; |
392 | } |
393 | regmap_field_write(field: priv->rf[index], val: enable ? 0 : 1); |
394 | } |
395 | |
396 | static void tsens_set_interrupt_v2(struct tsens_priv *priv, u32 hw_id, |
397 | enum tsens_irq_type irq_type, bool enable) |
398 | { |
399 | u32 index_mask = 0, index_clear = 0; |
400 | |
401 | /* |
402 | * To enable the interrupt flag for a sensor: |
403 | * - clear the mask bit |
404 | * To disable the interrupt flag for a sensor: |
405 | * - Mask further interrupts for this sensor |
406 | * - Write 1 followed by 0 to clear the interrupt |
407 | */ |
408 | switch (irq_type) { |
409 | case UPPER: |
410 | index_mask = UP_INT_MASK_0 + hw_id; |
411 | index_clear = UP_INT_CLEAR_0 + hw_id; |
412 | break; |
413 | case LOWER: |
414 | index_mask = LOW_INT_MASK_0 + hw_id; |
415 | index_clear = LOW_INT_CLEAR_0 + hw_id; |
416 | break; |
417 | case CRITICAL: |
418 | index_mask = CRIT_INT_MASK_0 + hw_id; |
419 | index_clear = CRIT_INT_CLEAR_0 + hw_id; |
420 | break; |
421 | } |
422 | |
423 | if (enable) { |
424 | regmap_field_write(field: priv->rf[index_mask], val: 0); |
425 | } else { |
426 | regmap_field_write(field: priv->rf[index_mask], val: 1); |
427 | regmap_field_write(field: priv->rf[index_clear], val: 1); |
428 | regmap_field_write(field: priv->rf[index_clear], val: 0); |
429 | } |
430 | } |
431 | |
432 | /** |
433 | * tsens_set_interrupt - Set state of an interrupt |
434 | * @priv: Pointer to tsens controller private data |
435 | * @hw_id: Hardware ID aka. sensor number |
436 | * @irq_type: irq_type from enum tsens_irq_type |
437 | * @enable: false = disable, true = enable |
438 | * |
439 | * Call IP-specific function to set state of an interrupt |
440 | * |
441 | * Return: void |
442 | */ |
443 | static void tsens_set_interrupt(struct tsens_priv *priv, u32 hw_id, |
444 | enum tsens_irq_type irq_type, bool enable) |
445 | { |
446 | dev_dbg(priv->dev, "[%u] %s: %s -> %s\n" , hw_id, __func__, |
447 | irq_type ? ((irq_type == 1) ? "UP" : "CRITICAL" ) : "LOW" , |
448 | enable ? "en" : "dis" ); |
449 | if (tsens_version(priv) > VER_1_X) |
450 | tsens_set_interrupt_v2(priv, hw_id, irq_type, enable); |
451 | else |
452 | tsens_set_interrupt_v1(priv, hw_id, irq_type, enable); |
453 | } |
454 | |
455 | /** |
456 | * tsens_threshold_violated - Check if a sensor temperature violated a preset threshold |
457 | * @priv: Pointer to tsens controller private data |
458 | * @hw_id: Hardware ID aka. sensor number |
459 | * @d: Pointer to irq state data |
460 | * |
461 | * Return: 0 if threshold was not violated, 1 if it was violated and negative |
462 | * errno in case of errors |
463 | */ |
464 | static int tsens_threshold_violated(struct tsens_priv *priv, u32 hw_id, |
465 | struct tsens_irq_data *d) |
466 | { |
467 | int ret; |
468 | |
469 | ret = regmap_field_read(field: priv->rf[UPPER_STATUS_0 + hw_id], val: &d->up_viol); |
470 | if (ret) |
471 | return ret; |
472 | ret = regmap_field_read(field: priv->rf[LOWER_STATUS_0 + hw_id], val: &d->low_viol); |
473 | if (ret) |
474 | return ret; |
475 | |
476 | if (priv->feat->crit_int) { |
477 | ret = regmap_field_read(field: priv->rf[CRITICAL_STATUS_0 + hw_id], |
478 | val: &d->crit_viol); |
479 | if (ret) |
480 | return ret; |
481 | } |
482 | |
483 | if (d->up_viol || d->low_viol || d->crit_viol) |
484 | return 1; |
485 | |
486 | return 0; |
487 | } |
488 | |
489 | static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id, |
490 | const struct tsens_sensor *s, |
491 | struct tsens_irq_data *d) |
492 | { |
493 | int ret; |
494 | |
495 | ret = regmap_field_read(field: priv->rf[UP_INT_CLEAR_0 + hw_id], val: &d->up_irq_clear); |
496 | if (ret) |
497 | return ret; |
498 | ret = regmap_field_read(field: priv->rf[LOW_INT_CLEAR_0 + hw_id], val: &d->low_irq_clear); |
499 | if (ret) |
500 | return ret; |
501 | if (tsens_version(priv) > VER_1_X) { |
502 | ret = regmap_field_read(field: priv->rf[UP_INT_MASK_0 + hw_id], val: &d->up_irq_mask); |
503 | if (ret) |
504 | return ret; |
505 | ret = regmap_field_read(field: priv->rf[LOW_INT_MASK_0 + hw_id], val: &d->low_irq_mask); |
506 | if (ret) |
507 | return ret; |
508 | ret = regmap_field_read(field: priv->rf[CRIT_INT_CLEAR_0 + hw_id], |
509 | val: &d->crit_irq_clear); |
510 | if (ret) |
511 | return ret; |
512 | ret = regmap_field_read(field: priv->rf[CRIT_INT_MASK_0 + hw_id], |
513 | val: &d->crit_irq_mask); |
514 | if (ret) |
515 | return ret; |
516 | |
517 | d->crit_thresh = tsens_hw_to_mC(s, field: CRIT_THRESH_0 + hw_id); |
518 | } else { |
519 | /* No mask register on older TSENS */ |
520 | d->up_irq_mask = 0; |
521 | d->low_irq_mask = 0; |
522 | d->crit_irq_clear = 0; |
523 | d->crit_irq_mask = 0; |
524 | d->crit_thresh = 0; |
525 | } |
526 | |
527 | d->up_thresh = tsens_hw_to_mC(s, field: UP_THRESH_0 + hw_id); |
528 | d->low_thresh = tsens_hw_to_mC(s, field: LOW_THRESH_0 + hw_id); |
529 | |
530 | dev_dbg(priv->dev, "[%u] %s%s: status(%u|%u|%u) | clr(%u|%u|%u) | mask(%u|%u|%u)\n" , |
531 | hw_id, __func__, |
532 | (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "" , |
533 | d->low_viol, d->up_viol, d->crit_viol, |
534 | d->low_irq_clear, d->up_irq_clear, d->crit_irq_clear, |
535 | d->low_irq_mask, d->up_irq_mask, d->crit_irq_mask); |
536 | dev_dbg(priv->dev, "[%u] %s%s: thresh: (%d:%d:%d)\n" , hw_id, __func__, |
537 | (d->up_viol || d->low_viol || d->crit_viol) ? "(V)" : "" , |
538 | d->low_thresh, d->up_thresh, d->crit_thresh); |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver) |
544 | { |
545 | if (ver > VER_1_X) |
546 | return mask & (1 << hw_id); |
547 | |
548 | /* v1, v0.1 don't have a irq mask register */ |
549 | return 0; |
550 | } |
551 | |
552 | /** |
553 | * tsens_critical_irq_thread() - Threaded handler for critical interrupts |
554 | * @irq: irq number |
555 | * @data: tsens controller private data |
556 | * |
557 | * Check FSM watchdog bark status and clear if needed. |
558 | * Check all sensors to find ones that violated their critical threshold limits. |
559 | * Clear and then re-enable the interrupt. |
560 | * |
561 | * The level-triggered interrupt might deassert if the temperature returned to |
562 | * within the threshold limits by the time the handler got scheduled. We |
563 | * consider the irq to have been handled in that case. |
564 | * |
565 | * Return: IRQ_HANDLED |
566 | */ |
567 | static irqreturn_t tsens_critical_irq_thread(int irq, void *data) |
568 | { |
569 | struct tsens_priv *priv = data; |
570 | struct tsens_irq_data d; |
571 | int temp, ret, i; |
572 | u32 wdog_status, wdog_count; |
573 | |
574 | if (priv->feat->has_watchdog) { |
575 | ret = regmap_field_read(field: priv->rf[WDOG_BARK_STATUS], |
576 | val: &wdog_status); |
577 | if (ret) |
578 | return ret; |
579 | |
580 | if (wdog_status) { |
581 | /* Clear WDOG interrupt */ |
582 | regmap_field_write(field: priv->rf[WDOG_BARK_CLEAR], val: 1); |
583 | regmap_field_write(field: priv->rf[WDOG_BARK_CLEAR], val: 0); |
584 | ret = regmap_field_read(field: priv->rf[WDOG_BARK_COUNT], |
585 | val: &wdog_count); |
586 | if (ret) |
587 | return ret; |
588 | if (wdog_count) |
589 | dev_dbg(priv->dev, "%s: watchdog count: %d\n" , |
590 | __func__, wdog_count); |
591 | |
592 | /* Fall through to handle critical interrupts if any */ |
593 | } |
594 | } |
595 | |
596 | for (i = 0; i < priv->num_sensors; i++) { |
597 | const struct tsens_sensor *s = &priv->sensor[i]; |
598 | u32 hw_id = s->hw_id; |
599 | |
600 | if (!s->tzd) |
601 | continue; |
602 | if (!tsens_threshold_violated(priv, hw_id, d: &d)) |
603 | continue; |
604 | ret = get_temp_tsens_valid(s, temp: &temp); |
605 | if (ret) { |
606 | dev_err(priv->dev, "[%u] %s: error reading sensor\n" , |
607 | hw_id, __func__); |
608 | continue; |
609 | } |
610 | |
611 | tsens_read_irq_state(priv, hw_id, s, d: &d); |
612 | if (d.crit_viol && |
613 | !masked_irq(hw_id, mask: d.crit_irq_mask, ver: tsens_version(priv))) { |
614 | /* Mask critical interrupts, unused on Linux */ |
615 | tsens_set_interrupt(priv, hw_id, irq_type: CRITICAL, enable: false); |
616 | } |
617 | } |
618 | |
619 | return IRQ_HANDLED; |
620 | } |
621 | |
622 | /** |
623 | * tsens_irq_thread - Threaded interrupt handler for uplow interrupts |
624 | * @irq: irq number |
625 | * @data: tsens controller private data |
626 | * |
627 | * Check all sensors to find ones that violated their threshold limits. If the |
628 | * temperature is still outside the limits, call thermal_zone_device_update() to |
629 | * update the thresholds, else re-enable the interrupts. |
630 | * |
631 | * The level-triggered interrupt might deassert if the temperature returned to |
632 | * within the threshold limits by the time the handler got scheduled. We |
633 | * consider the irq to have been handled in that case. |
634 | * |
635 | * Return: IRQ_HANDLED |
636 | */ |
637 | static irqreturn_t tsens_irq_thread(int irq, void *data) |
638 | { |
639 | struct tsens_priv *priv = data; |
640 | struct tsens_irq_data d; |
641 | int i; |
642 | |
643 | for (i = 0; i < priv->num_sensors; i++) { |
644 | const struct tsens_sensor *s = &priv->sensor[i]; |
645 | u32 hw_id = s->hw_id; |
646 | |
647 | if (!s->tzd) |
648 | continue; |
649 | if (!tsens_threshold_violated(priv, hw_id, d: &d)) |
650 | continue; |
651 | |
652 | thermal_zone_device_update(s->tzd, THERMAL_EVENT_UNSPECIFIED); |
653 | |
654 | if (tsens_version(priv) < VER_0_1) { |
655 | /* Constraint: There is only 1 interrupt control register for all |
656 | * 11 temperature sensor. So monitoring more than 1 sensor based |
657 | * on interrupts will yield inconsistent result. To overcome this |
658 | * issue we will monitor only sensor 0 which is the master sensor. |
659 | */ |
660 | break; |
661 | } |
662 | } |
663 | |
664 | return IRQ_HANDLED; |
665 | } |
666 | |
667 | /** |
668 | * tsens_combined_irq_thread() - Threaded interrupt handler for combined interrupts |
669 | * @irq: irq number |
670 | * @data: tsens controller private data |
671 | * |
672 | * Handle the combined interrupt as if it were 2 separate interrupts, so call the |
673 | * critical handler first and then the up/low one. |
674 | * |
675 | * Return: IRQ_HANDLED |
676 | */ |
677 | static irqreturn_t tsens_combined_irq_thread(int irq, void *data) |
678 | { |
679 | irqreturn_t ret; |
680 | |
681 | ret = tsens_critical_irq_thread(irq, data); |
682 | if (ret != IRQ_HANDLED) |
683 | return ret; |
684 | |
685 | return tsens_irq_thread(irq, data); |
686 | } |
687 | |
688 | static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high) |
689 | { |
690 | struct tsens_sensor *s = thermal_zone_device_priv(tzd: tz); |
691 | struct tsens_priv *priv = s->priv; |
692 | struct device *dev = priv->dev; |
693 | struct tsens_irq_data d; |
694 | unsigned long flags; |
695 | int high_val, low_val, cl_high, cl_low; |
696 | u32 hw_id = s->hw_id; |
697 | |
698 | if (tsens_version(priv) < VER_0_1) { |
699 | /* Pre v0.1 IP had a single register for each type of interrupt |
700 | * and thresholds |
701 | */ |
702 | hw_id = 0; |
703 | } |
704 | |
705 | dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n" , |
706 | hw_id, __func__, low, high); |
707 | |
708 | cl_high = clamp_val(high, priv->feat->trip_min_temp, priv->feat->trip_max_temp); |
709 | cl_low = clamp_val(low, priv->feat->trip_min_temp, priv->feat->trip_max_temp); |
710 | |
711 | high_val = tsens_mC_to_hw(s, temp: cl_high); |
712 | low_val = tsens_mC_to_hw(s, temp: cl_low); |
713 | |
714 | spin_lock_irqsave(&priv->ul_lock, flags); |
715 | |
716 | tsens_read_irq_state(priv, hw_id, s, d: &d); |
717 | |
718 | /* Write the new thresholds and clear the status */ |
719 | regmap_field_write(field: priv->rf[LOW_THRESH_0 + hw_id], val: low_val); |
720 | regmap_field_write(field: priv->rf[UP_THRESH_0 + hw_id], val: high_val); |
721 | tsens_set_interrupt(priv, hw_id, irq_type: LOWER, enable: true); |
722 | tsens_set_interrupt(priv, hw_id, irq_type: UPPER, enable: true); |
723 | |
724 | spin_unlock_irqrestore(lock: &priv->ul_lock, flags); |
725 | |
726 | dev_dbg(dev, "[%u] %s: (%d:%d)->(%d:%d)\n" , |
727 | hw_id, __func__, d.low_thresh, d.up_thresh, cl_low, cl_high); |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | static int tsens_enable_irq(struct tsens_priv *priv) |
733 | { |
734 | int ret; |
735 | int val = tsens_version(priv) > VER_1_X ? 7 : 1; |
736 | |
737 | ret = regmap_field_write(field: priv->rf[INT_EN], val); |
738 | if (ret < 0) |
739 | dev_err(priv->dev, "%s: failed to enable interrupts\n" , |
740 | __func__); |
741 | |
742 | return ret; |
743 | } |
744 | |
745 | static void tsens_disable_irq(struct tsens_priv *priv) |
746 | { |
747 | regmap_field_write(field: priv->rf[INT_EN], val: 0); |
748 | } |
749 | |
750 | int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp) |
751 | { |
752 | struct tsens_priv *priv = s->priv; |
753 | int hw_id = s->hw_id; |
754 | u32 temp_idx = LAST_TEMP_0 + hw_id; |
755 | u32 valid_idx = VALID_0 + hw_id; |
756 | u32 valid; |
757 | int ret; |
758 | |
759 | /* VER_0 doesn't have VALID bit */ |
760 | if (tsens_version(priv) == VER_0) |
761 | goto get_temp; |
762 | |
763 | /* Valid bit is 0 for 6 AHB clock cycles. |
764 | * At 19.2MHz, 1 AHB clock is ~60ns. |
765 | * We should enter this loop very, very rarely. |
766 | * Wait 1 us since it's the min of poll_timeout macro. |
767 | * Old value was 400 ns. |
768 | */ |
769 | ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid, |
770 | valid, 1, 20 * USEC_PER_MSEC); |
771 | if (ret) |
772 | return ret; |
773 | |
774 | get_temp: |
775 | /* Valid bit is set, OK to read the temperature */ |
776 | *temp = tsens_hw_to_mC(s, field: temp_idx); |
777 | |
778 | return 0; |
779 | } |
780 | |
781 | int get_temp_common(const struct tsens_sensor *s, int *temp) |
782 | { |
783 | struct tsens_priv *priv = s->priv; |
784 | int hw_id = s->hw_id; |
785 | int last_temp = 0, ret, trdy; |
786 | unsigned long timeout; |
787 | |
788 | timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); |
789 | do { |
790 | if (tsens_version(priv) == VER_0) { |
791 | ret = regmap_field_read(field: priv->rf[TRDY], val: &trdy); |
792 | if (ret) |
793 | return ret; |
794 | if (!trdy) |
795 | continue; |
796 | } |
797 | |
798 | ret = regmap_field_read(field: priv->rf[LAST_TEMP_0 + hw_id], val: &last_temp); |
799 | if (ret) |
800 | return ret; |
801 | |
802 | *temp = code_to_degc(adc_code: last_temp, s) * 1000; |
803 | |
804 | return 0; |
805 | } while (time_before(jiffies, timeout)); |
806 | |
807 | return -ETIMEDOUT; |
808 | } |
809 | |
810 | #ifdef CONFIG_DEBUG_FS |
811 | static int dbg_sensors_show(struct seq_file *s, void *data) |
812 | { |
813 | struct platform_device *pdev = s->private; |
814 | struct tsens_priv *priv = platform_get_drvdata(pdev); |
815 | int i; |
816 | |
817 | seq_printf(m: s, fmt: "max: %2d\nnum: %2d\n\n" , |
818 | priv->feat->max_sensors, priv->num_sensors); |
819 | |
820 | seq_puts(m: s, s: " id slope offset\n--------------------------\n" ); |
821 | for (i = 0; i < priv->num_sensors; i++) { |
822 | seq_printf(m: s, fmt: "%8d %8d %8d\n" , priv->sensor[i].hw_id, |
823 | priv->sensor[i].slope, priv->sensor[i].offset); |
824 | } |
825 | |
826 | return 0; |
827 | } |
828 | |
829 | static int dbg_version_show(struct seq_file *s, void *data) |
830 | { |
831 | struct platform_device *pdev = s->private; |
832 | struct tsens_priv *priv = platform_get_drvdata(pdev); |
833 | u32 maj_ver, min_ver, step_ver; |
834 | int ret; |
835 | |
836 | if (tsens_version(priv) > VER_0_1) { |
837 | ret = regmap_field_read(field: priv->rf[VER_MAJOR], val: &maj_ver); |
838 | if (ret) |
839 | return ret; |
840 | ret = regmap_field_read(field: priv->rf[VER_MINOR], val: &min_ver); |
841 | if (ret) |
842 | return ret; |
843 | ret = regmap_field_read(field: priv->rf[VER_STEP], val: &step_ver); |
844 | if (ret) |
845 | return ret; |
846 | seq_printf(m: s, fmt: "%d.%d.%d\n" , maj_ver, min_ver, step_ver); |
847 | } else { |
848 | seq_printf(m: s, fmt: "0.%d.0\n" , priv->feat->ver_major); |
849 | } |
850 | |
851 | return 0; |
852 | } |
853 | |
854 | DEFINE_SHOW_ATTRIBUTE(dbg_version); |
855 | DEFINE_SHOW_ATTRIBUTE(dbg_sensors); |
856 | |
857 | static void tsens_debug_init(struct platform_device *pdev) |
858 | { |
859 | struct tsens_priv *priv = platform_get_drvdata(pdev); |
860 | |
861 | priv->debug_root = debugfs_lookup(name: "tsens" , NULL); |
862 | if (!priv->debug_root) |
863 | priv->debug_root = debugfs_create_dir(name: "tsens" , NULL); |
864 | |
865 | /* A directory for each instance of the TSENS IP */ |
866 | priv->debug = debugfs_create_dir(name: dev_name(dev: &pdev->dev), parent: priv->debug_root); |
867 | debugfs_create_file(name: "version" , mode: 0444, parent: priv->debug, data: pdev, fops: &dbg_version_fops); |
868 | debugfs_create_file(name: "sensors" , mode: 0444, parent: priv->debug, data: pdev, fops: &dbg_sensors_fops); |
869 | } |
870 | #else |
871 | static inline void tsens_debug_init(struct platform_device *pdev) {} |
872 | #endif |
873 | |
874 | static const struct regmap_config tsens_config = { |
875 | .name = "tm" , |
876 | .reg_bits = 32, |
877 | .val_bits = 32, |
878 | .reg_stride = 4, |
879 | }; |
880 | |
881 | static const struct regmap_config tsens_srot_config = { |
882 | .name = "srot" , |
883 | .reg_bits = 32, |
884 | .val_bits = 32, |
885 | .reg_stride = 4, |
886 | }; |
887 | |
888 | int __init init_common(struct tsens_priv *priv) |
889 | { |
890 | void __iomem *tm_base, *srot_base; |
891 | struct device *dev = priv->dev; |
892 | u32 ver_minor; |
893 | struct resource *res; |
894 | u32 enabled; |
895 | int ret, i, j; |
896 | struct platform_device *op = of_find_device_by_node(np: priv->dev->of_node); |
897 | |
898 | if (!op) |
899 | return -EINVAL; |
900 | |
901 | if (op->num_resources > 1) { |
902 | /* DT with separate SROT and TM address space */ |
903 | priv->tm_offset = 0; |
904 | res = platform_get_resource(op, IORESOURCE_MEM, 1); |
905 | srot_base = devm_ioremap_resource(dev, res); |
906 | if (IS_ERR(ptr: srot_base)) { |
907 | ret = PTR_ERR(ptr: srot_base); |
908 | goto err_put_device; |
909 | } |
910 | |
911 | priv->srot_map = devm_regmap_init_mmio(dev, srot_base, |
912 | &tsens_srot_config); |
913 | if (IS_ERR(ptr: priv->srot_map)) { |
914 | ret = PTR_ERR(ptr: priv->srot_map); |
915 | goto err_put_device; |
916 | } |
917 | } else { |
918 | /* old DTs where SROT and TM were in a contiguous 2K block */ |
919 | priv->tm_offset = 0x1000; |
920 | } |
921 | |
922 | if (tsens_version(priv) >= VER_0_1) { |
923 | res = platform_get_resource(op, IORESOURCE_MEM, 0); |
924 | tm_base = devm_ioremap_resource(dev, res); |
925 | if (IS_ERR(ptr: tm_base)) { |
926 | ret = PTR_ERR(ptr: tm_base); |
927 | goto err_put_device; |
928 | } |
929 | |
930 | priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); |
931 | } else { /* VER_0 share the same gcc regs using a syscon */ |
932 | struct device *parent = priv->dev->parent; |
933 | |
934 | if (parent) |
935 | priv->tm_map = syscon_node_to_regmap(np: parent->of_node); |
936 | } |
937 | |
938 | if (IS_ERR_OR_NULL(ptr: priv->tm_map)) { |
939 | if (!priv->tm_map) |
940 | ret = -ENODEV; |
941 | else |
942 | ret = PTR_ERR(ptr: priv->tm_map); |
943 | goto err_put_device; |
944 | } |
945 | |
946 | /* VER_0 have only tm_map */ |
947 | if (!priv->srot_map) |
948 | priv->srot_map = priv->tm_map; |
949 | |
950 | if (tsens_version(priv) > VER_0_1) { |
951 | for (i = VER_MAJOR; i <= VER_STEP; i++) { |
952 | priv->rf[i] = devm_regmap_field_alloc(dev, regmap: priv->srot_map, |
953 | reg_field: priv->fields[i]); |
954 | if (IS_ERR(ptr: priv->rf[i])) { |
955 | ret = PTR_ERR(ptr: priv->rf[i]); |
956 | goto err_put_device; |
957 | } |
958 | } |
959 | ret = regmap_field_read(field: priv->rf[VER_MINOR], val: &ver_minor); |
960 | if (ret) |
961 | goto err_put_device; |
962 | } |
963 | |
964 | priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, regmap: priv->srot_map, |
965 | reg_field: priv->fields[TSENS_EN]); |
966 | if (IS_ERR(ptr: priv->rf[TSENS_EN])) { |
967 | ret = PTR_ERR(ptr: priv->rf[TSENS_EN]); |
968 | goto err_put_device; |
969 | } |
970 | /* in VER_0 TSENS need to be explicitly enabled */ |
971 | if (tsens_version(priv) == VER_0) |
972 | regmap_field_write(field: priv->rf[TSENS_EN], val: 1); |
973 | |
974 | ret = regmap_field_read(field: priv->rf[TSENS_EN], val: &enabled); |
975 | if (ret) |
976 | goto err_put_device; |
977 | if (!enabled) { |
978 | dev_err(dev, "%s: device not enabled\n" , __func__); |
979 | ret = -ENODEV; |
980 | goto err_put_device; |
981 | } |
982 | |
983 | priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, regmap: priv->srot_map, |
984 | reg_field: priv->fields[SENSOR_EN]); |
985 | if (IS_ERR(ptr: priv->rf[SENSOR_EN])) { |
986 | ret = PTR_ERR(ptr: priv->rf[SENSOR_EN]); |
987 | goto err_put_device; |
988 | } |
989 | priv->rf[INT_EN] = devm_regmap_field_alloc(dev, regmap: priv->tm_map, |
990 | reg_field: priv->fields[INT_EN]); |
991 | if (IS_ERR(ptr: priv->rf[INT_EN])) { |
992 | ret = PTR_ERR(ptr: priv->rf[INT_EN]); |
993 | goto err_put_device; |
994 | } |
995 | |
996 | priv->rf[TSENS_SW_RST] = |
997 | devm_regmap_field_alloc(dev, regmap: priv->srot_map, reg_field: priv->fields[TSENS_SW_RST]); |
998 | if (IS_ERR(ptr: priv->rf[TSENS_SW_RST])) { |
999 | ret = PTR_ERR(ptr: priv->rf[TSENS_SW_RST]); |
1000 | goto err_put_device; |
1001 | } |
1002 | |
1003 | priv->rf[TRDY] = devm_regmap_field_alloc(dev, regmap: priv->tm_map, reg_field: priv->fields[TRDY]); |
1004 | if (IS_ERR(ptr: priv->rf[TRDY])) { |
1005 | ret = PTR_ERR(ptr: priv->rf[TRDY]); |
1006 | goto err_put_device; |
1007 | } |
1008 | |
1009 | /* This loop might need changes if enum regfield_ids is reordered */ |
1010 | for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { |
1011 | for (i = 0; i < priv->feat->max_sensors; i++) { |
1012 | int idx = j + i; |
1013 | |
1014 | priv->rf[idx] = devm_regmap_field_alloc(dev, |
1015 | regmap: priv->tm_map, |
1016 | reg_field: priv->fields[idx]); |
1017 | if (IS_ERR(ptr: priv->rf[idx])) { |
1018 | ret = PTR_ERR(ptr: priv->rf[idx]); |
1019 | goto err_put_device; |
1020 | } |
1021 | } |
1022 | } |
1023 | |
1024 | if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { |
1025 | /* Loop might need changes if enum regfield_ids is reordered */ |
1026 | for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { |
1027 | for (i = 0; i < priv->feat->max_sensors; i++) { |
1028 | int idx = j + i; |
1029 | |
1030 | priv->rf[idx] = |
1031 | devm_regmap_field_alloc(dev, |
1032 | regmap: priv->tm_map, |
1033 | reg_field: priv->fields[idx]); |
1034 | if (IS_ERR(ptr: priv->rf[idx])) { |
1035 | ret = PTR_ERR(ptr: priv->rf[idx]); |
1036 | goto err_put_device; |
1037 | } |
1038 | } |
1039 | } |
1040 | } |
1041 | |
1042 | if (tsens_version(priv) > VER_1_X && ver_minor > 2) { |
1043 | /* Watchdog is present only on v2.3+ */ |
1044 | priv->feat->has_watchdog = 1; |
1045 | for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) { |
1046 | priv->rf[i] = devm_regmap_field_alloc(dev, regmap: priv->tm_map, |
1047 | reg_field: priv->fields[i]); |
1048 | if (IS_ERR(ptr: priv->rf[i])) { |
1049 | ret = PTR_ERR(ptr: priv->rf[i]); |
1050 | goto err_put_device; |
1051 | } |
1052 | } |
1053 | /* |
1054 | * Watchdog is already enabled, unmask the bark. |
1055 | * Disable cycle completion monitoring |
1056 | */ |
1057 | regmap_field_write(field: priv->rf[WDOG_BARK_MASK], val: 0); |
1058 | regmap_field_write(field: priv->rf[CC_MON_MASK], val: 1); |
1059 | } |
1060 | |
1061 | spin_lock_init(&priv->ul_lock); |
1062 | |
1063 | /* VER_0 interrupt doesn't need to be enabled */ |
1064 | if (tsens_version(priv) >= VER_0_1) |
1065 | tsens_enable_irq(priv); |
1066 | |
1067 | err_put_device: |
1068 | put_device(dev: &op->dev); |
1069 | return ret; |
1070 | } |
1071 | |
1072 | static int tsens_get_temp(struct thermal_zone_device *tz, int *temp) |
1073 | { |
1074 | struct tsens_sensor *s = thermal_zone_device_priv(tzd: tz); |
1075 | struct tsens_priv *priv = s->priv; |
1076 | |
1077 | return priv->ops->get_temp(s, temp); |
1078 | } |
1079 | |
1080 | static int __maybe_unused tsens_suspend(struct device *dev) |
1081 | { |
1082 | struct tsens_priv *priv = dev_get_drvdata(dev); |
1083 | |
1084 | if (priv->ops && priv->ops->suspend) |
1085 | return priv->ops->suspend(priv); |
1086 | |
1087 | return 0; |
1088 | } |
1089 | |
1090 | static int __maybe_unused tsens_resume(struct device *dev) |
1091 | { |
1092 | struct tsens_priv *priv = dev_get_drvdata(dev); |
1093 | |
1094 | if (priv->ops && priv->ops->resume) |
1095 | return priv->ops->resume(priv); |
1096 | |
1097 | return 0; |
1098 | } |
1099 | |
1100 | static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); |
1101 | |
1102 | static const struct of_device_id tsens_table[] = { |
1103 | { |
1104 | .compatible = "qcom,ipq8064-tsens" , |
1105 | .data = &data_8960, |
1106 | }, { |
1107 | .compatible = "qcom,ipq8074-tsens" , |
1108 | .data = &data_ipq8074, |
1109 | }, { |
1110 | .compatible = "qcom,mdm9607-tsens" , |
1111 | .data = &data_9607, |
1112 | }, { |
1113 | .compatible = "qcom,msm8226-tsens" , |
1114 | .data = &data_8226, |
1115 | }, { |
1116 | .compatible = "qcom,msm8909-tsens" , |
1117 | .data = &data_8909, |
1118 | }, { |
1119 | .compatible = "qcom,msm8916-tsens" , |
1120 | .data = &data_8916, |
1121 | }, { |
1122 | .compatible = "qcom,msm8939-tsens" , |
1123 | .data = &data_8939, |
1124 | }, { |
1125 | .compatible = "qcom,msm8956-tsens" , |
1126 | .data = &data_8956, |
1127 | }, { |
1128 | .compatible = "qcom,msm8960-tsens" , |
1129 | .data = &data_8960, |
1130 | }, { |
1131 | .compatible = "qcom,msm8974-tsens" , |
1132 | .data = &data_8974, |
1133 | }, { |
1134 | .compatible = "qcom,msm8976-tsens" , |
1135 | .data = &data_8976, |
1136 | }, { |
1137 | .compatible = "qcom,msm8996-tsens" , |
1138 | .data = &data_8996, |
1139 | }, { |
1140 | .compatible = "qcom,tsens-v1" , |
1141 | .data = &data_tsens_v1, |
1142 | }, { |
1143 | .compatible = "qcom,tsens-v2" , |
1144 | .data = &data_tsens_v2, |
1145 | }, |
1146 | {} |
1147 | }; |
1148 | MODULE_DEVICE_TABLE(of, tsens_table); |
1149 | |
1150 | static const struct thermal_zone_device_ops tsens_of_ops = { |
1151 | .get_temp = tsens_get_temp, |
1152 | .set_trips = tsens_set_trips, |
1153 | }; |
1154 | |
1155 | static int tsens_register_irq(struct tsens_priv *priv, char *irqname, |
1156 | irq_handler_t thread_fn) |
1157 | { |
1158 | struct platform_device *pdev; |
1159 | int ret, irq; |
1160 | |
1161 | pdev = of_find_device_by_node(np: priv->dev->of_node); |
1162 | if (!pdev) |
1163 | return -ENODEV; |
1164 | |
1165 | irq = platform_get_irq_byname(pdev, irqname); |
1166 | if (irq < 0) { |
1167 | ret = irq; |
1168 | /* For old DTs with no IRQ defined */ |
1169 | if (irq == -ENXIO) |
1170 | ret = 0; |
1171 | } else { |
1172 | /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ |
1173 | if (tsens_version(priv) == VER_0) |
1174 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, |
1175 | handler: thread_fn, NULL, |
1176 | IRQF_TRIGGER_RISING, |
1177 | devname: dev_name(dev: &pdev->dev), |
1178 | dev_id: priv); |
1179 | else |
1180 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq, NULL, |
1181 | thread_fn, IRQF_ONESHOT, |
1182 | devname: dev_name(dev: &pdev->dev), |
1183 | dev_id: priv); |
1184 | |
1185 | if (ret) |
1186 | dev_err(&pdev->dev, "%s: failed to get irq\n" , |
1187 | __func__); |
1188 | else |
1189 | enable_irq_wake(irq); |
1190 | } |
1191 | |
1192 | put_device(dev: &pdev->dev); |
1193 | return ret; |
1194 | } |
1195 | |
1196 | static int tsens_register(struct tsens_priv *priv) |
1197 | { |
1198 | int i, ret; |
1199 | struct thermal_zone_device *tzd; |
1200 | |
1201 | for (i = 0; i < priv->num_sensors; i++) { |
1202 | priv->sensor[i].priv = priv; |
1203 | tzd = devm_thermal_of_zone_register(dev: priv->dev, id: priv->sensor[i].hw_id, |
1204 | data: &priv->sensor[i], |
1205 | ops: &tsens_of_ops); |
1206 | if (IS_ERR(ptr: tzd)) |
1207 | continue; |
1208 | priv->sensor[i].tzd = tzd; |
1209 | if (priv->ops->enable) |
1210 | priv->ops->enable(priv, i); |
1211 | |
1212 | devm_thermal_add_hwmon_sysfs(dev: priv->dev, tz: tzd); |
1213 | } |
1214 | |
1215 | /* VER_0 require to set MIN and MAX THRESH |
1216 | * These 2 regs are set using the: |
1217 | * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C |
1218 | * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C |
1219 | */ |
1220 | if (tsens_version(priv) < VER_0_1) { |
1221 | regmap_field_write(field: priv->rf[CRIT_THRESH_0], |
1222 | val: tsens_mC_to_hw(s: priv->sensor, temp: 120000)); |
1223 | |
1224 | regmap_field_write(field: priv->rf[CRIT_THRESH_1], |
1225 | val: tsens_mC_to_hw(s: priv->sensor, temp: 0)); |
1226 | } |
1227 | |
1228 | if (priv->feat->combo_int) { |
1229 | ret = tsens_register_irq(priv, irqname: "combined" , |
1230 | thread_fn: tsens_combined_irq_thread); |
1231 | } else { |
1232 | ret = tsens_register_irq(priv, irqname: "uplow" , thread_fn: tsens_irq_thread); |
1233 | if (ret < 0) |
1234 | return ret; |
1235 | |
1236 | if (priv->feat->crit_int) |
1237 | ret = tsens_register_irq(priv, irqname: "critical" , |
1238 | thread_fn: tsens_critical_irq_thread); |
1239 | } |
1240 | |
1241 | return ret; |
1242 | } |
1243 | |
1244 | static int tsens_probe(struct platform_device *pdev) |
1245 | { |
1246 | int ret, i; |
1247 | struct device *dev; |
1248 | struct device_node *np; |
1249 | struct tsens_priv *priv; |
1250 | const struct tsens_plat_data *data; |
1251 | const struct of_device_id *id; |
1252 | u32 num_sensors; |
1253 | |
1254 | if (pdev->dev.of_node) |
1255 | dev = &pdev->dev; |
1256 | else |
1257 | dev = pdev->dev.parent; |
1258 | |
1259 | np = dev->of_node; |
1260 | |
1261 | id = of_match_node(matches: tsens_table, node: np); |
1262 | if (id) |
1263 | data = id->data; |
1264 | else |
1265 | data = &data_8960; |
1266 | |
1267 | num_sensors = data->num_sensors; |
1268 | |
1269 | if (np) |
1270 | of_property_read_u32(np, propname: "#qcom,sensors" , out_value: &num_sensors); |
1271 | |
1272 | if (num_sensors <= 0) { |
1273 | dev_err(dev, "%s: invalid number of sensors\n" , __func__); |
1274 | return -EINVAL; |
1275 | } |
1276 | |
1277 | priv = devm_kzalloc(dev, |
1278 | struct_size(priv, sensor, num_sensors), |
1279 | GFP_KERNEL); |
1280 | if (!priv) |
1281 | return -ENOMEM; |
1282 | |
1283 | priv->dev = dev; |
1284 | priv->num_sensors = num_sensors; |
1285 | priv->ops = data->ops; |
1286 | for (i = 0; i < priv->num_sensors; i++) { |
1287 | if (data->hw_ids) |
1288 | priv->sensor[i].hw_id = data->hw_ids[i]; |
1289 | else |
1290 | priv->sensor[i].hw_id = i; |
1291 | } |
1292 | priv->feat = data->feat; |
1293 | priv->fields = data->fields; |
1294 | |
1295 | platform_set_drvdata(pdev, data: priv); |
1296 | |
1297 | if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) |
1298 | return -EINVAL; |
1299 | |
1300 | ret = priv->ops->init(priv); |
1301 | if (ret < 0) { |
1302 | dev_err(dev, "%s: init failed\n" , __func__); |
1303 | return ret; |
1304 | } |
1305 | |
1306 | if (priv->ops->calibrate) { |
1307 | ret = priv->ops->calibrate(priv); |
1308 | if (ret < 0) { |
1309 | if (ret != -EPROBE_DEFER) |
1310 | dev_err(dev, "%s: calibration failed\n" , __func__); |
1311 | return ret; |
1312 | } |
1313 | } |
1314 | |
1315 | ret = tsens_register(priv); |
1316 | if (!ret) |
1317 | tsens_debug_init(pdev); |
1318 | |
1319 | return ret; |
1320 | } |
1321 | |
1322 | static void tsens_remove(struct platform_device *pdev) |
1323 | { |
1324 | struct tsens_priv *priv = platform_get_drvdata(pdev); |
1325 | |
1326 | debugfs_remove_recursive(dentry: priv->debug_root); |
1327 | tsens_disable_irq(priv); |
1328 | if (priv->ops->disable) |
1329 | priv->ops->disable(priv); |
1330 | } |
1331 | |
1332 | static struct platform_driver tsens_driver = { |
1333 | .probe = tsens_probe, |
1334 | .remove_new = tsens_remove, |
1335 | .driver = { |
1336 | .name = "qcom-tsens" , |
1337 | .pm = &tsens_pm_ops, |
1338 | .of_match_table = tsens_table, |
1339 | }, |
1340 | }; |
1341 | module_platform_driver(tsens_driver); |
1342 | |
1343 | MODULE_LICENSE("GPL v2" ); |
1344 | MODULE_DESCRIPTION("QCOM Temperature Sensor driver" ); |
1345 | MODULE_ALIAS("platform:qcom-tsens" ); |
1346 | |