Commit | Line | Data |
---|---|---|
770324a4 | 1 | // SPDX-License-Identifier: GPL-2.0 |
d059c739 RN |
2 | /* |
3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. | |
770324a4 | 4 | * Copyright (c) 2018, Linaro Limited |
d059c739 RN |
5 | */ |
6 | ||
432121ad | 7 | #include <linux/bitops.h> |
c1997054 | 8 | #include <linux/regmap.h> |
d059c739 RN |
9 | #include "tsens.h" |
10 | ||
c1997054 AK |
11 | /* ----- SROT ------ */ |
12 | #define SROT_HW_VER_OFF 0x0000 | |
13 | #define SROT_CTRL_OFF 0x0004 | |
14 | ||
15 | /* ----- TM ------ */ | |
16 | #define TM_INT_EN_OFF 0x0004 | |
17 | #define TM_UPPER_LOWER_INT_STATUS_OFF 0x0008 | |
18 | #define TM_UPPER_LOWER_INT_CLEAR_OFF 0x000c | |
19 | #define TM_UPPER_LOWER_INT_MASK_OFF 0x0010 | |
20 | #define TM_CRITICAL_INT_STATUS_OFF 0x0014 | |
21 | #define TM_CRITICAL_INT_CLEAR_OFF 0x0018 | |
22 | #define TM_CRITICAL_INT_MASK_OFF 0x001c | |
23 | #define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020 | |
24 | #define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060 | |
25 | #define TM_Sn_STATUS_OFF 0x00a0 | |
26 | #define TM_TRDY_OFF 0x00e4 | |
27 | ||
dbdaa582 | 28 | static int get_temp_tsens_v2(struct tsens_priv *priv, int i, int *temp) |
d059c739 | 29 | { |
dbdaa582 | 30 | struct tsens_sensor *s = &priv->sensor[i]; |
c1997054 AK |
31 | u32 temp_idx = LAST_TEMP_0 + s->hw_id; |
32 | u32 valid_idx = VALID_0 + s->hw_id; | |
dbdaa582 | 33 | u32 last_temp = 0, valid, mask; |
432121ad | 34 | int ret; |
d059c739 | 35 | |
c1997054 | 36 | ret = regmap_field_read(priv->rf[valid_idx], &valid); |
d059c739 RN |
37 | if (ret) |
38 | return ret; | |
dbdaa582 AK |
39 | while (!valid) { |
40 | /* Valid bit is 0 for 6 AHB clock cycles. | |
41 | * At 19.2MHz, 1 AHB clock is ~60ns. | |
42 | * We should enter this loop very, very rarely. | |
43 | */ | |
44 | ndelay(400); | |
45 | ret = regmap_field_read(priv->rf[valid_idx], &valid); | |
46 | if (ret) | |
47 | return ret; | |
d059c739 RN |
48 | } |
49 | ||
dbdaa582 AK |
50 | /* Valid bit is set, OK to read the temperature */ |
51 | ret = regmap_field_read(priv->rf[temp_idx], &last_temp); | |
c1997054 AK |
52 | if (ret) |
53 | return ret; | |
d059c739 | 54 | |
dbdaa582 AK |
55 | mask = GENMASK(priv->fields[LAST_TEMP_0].msb, |
56 | priv->fields[LAST_TEMP_0].lsb); | |
432121ad | 57 | /* Convert temperature from deciCelsius to milliCelsius */ |
dbdaa582 | 58 | *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; |
d059c739 RN |
59 | |
60 | return 0; | |
61 | } | |
62 | ||
c1997054 AK |
63 | /* v2.x: 8996, 8998, sdm845 */ |
64 | ||
65 | static const struct tsens_features tsens_v2_feat = { | |
66 | .ver_major = VER_2_X, | |
67 | .crit_int = 1, | |
68 | .adc = 0, | |
69 | .srot_split = 1, | |
1b6e3e51 | 70 | .max_sensors = 16, |
c1997054 AK |
71 | }; |
72 | ||
73 | static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { | |
74 | /* ----- SROT ------ */ | |
75 | /* VERSION */ | |
76 | [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31), | |
77 | [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27), | |
78 | [VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15), | |
79 | /* CTRL_OFF */ | |
80 | [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), | |
81 | [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), | |
3e6a8fb3 | 82 | [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18), |
c1997054 AK |
83 | |
84 | /* ----- TM ------ */ | |
85 | /* INTERRUPT ENABLE */ | |
86 | /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */ | |
87 | [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 2), | |
88 | ||
89 | /* Sn_STATUS */ | |
90 | REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 11), | |
91 | REG_FIELD_FOR_EACH_SENSOR16(VALID, TM_Sn_STATUS_OFF, 21, 21), | |
92 | REG_FIELD_FOR_EACH_SENSOR16(MIN_STATUS, TM_Sn_STATUS_OFF, 16, 16), | |
93 | REG_FIELD_FOR_EACH_SENSOR16(LOWER_STATUS, TM_Sn_STATUS_OFF, 17, 17), | |
94 | REG_FIELD_FOR_EACH_SENSOR16(UPPER_STATUS, TM_Sn_STATUS_OFF, 18, 18), | |
95 | REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19, 19), | |
96 | REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS, TM_Sn_STATUS_OFF, 20, 20), | |
97 | ||
98 | /* TRDY: 1=ready, 0=in progress */ | |
99 | [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), | |
100 | }; | |
101 | ||
770324a4 | 102 | static const struct tsens_ops ops_generic_v2 = { |
d059c739 | 103 | .init = init_common, |
770324a4 | 104 | .get_temp = get_temp_tsens_v2, |
d059c739 RN |
105 | }; |
106 | ||
3c040ce0 | 107 | const struct tsens_plat_data data_tsens_v2 = { |
c1997054 AK |
108 | .ops = &ops_generic_v2, |
109 | .feat = &tsens_v2_feat, | |
110 | .fields = tsens_v2_regfields, | |
191dc74b AK |
111 | }; |
112 | ||
113 | /* Kept around for backward compatibility with old msm8996.dtsi */ | |
3c040ce0 | 114 | const struct tsens_plat_data data_8996 = { |
d059c739 | 115 | .num_sensors = 13, |
770324a4 | 116 | .ops = &ops_generic_v2, |
c1997054 AK |
117 | .feat = &tsens_v2_feat, |
118 | .fields = tsens_v2_regfields, | |
d059c739 | 119 | }; |