Commit | Line | Data |
---|---|---|
2d71d8de | 1 | // SPDX-License-Identifier: GPL-2.0 |
20d4fd84 RN |
2 | /* |
3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. | |
20d4fd84 RN |
4 | */ |
5 | ||
6 | #include <linux/platform_device.h> | |
7 | #include <linux/delay.h> | |
8 | #include <linux/bitops.h> | |
9 | #include <linux/regmap.h> | |
10 | #include <linux/thermal.h> | |
11 | #include "tsens.h" | |
12 | ||
20d4fd84 RN |
13 | #define CONFIG_ADDR 0x3640 |
14 | #define CONFIG_ADDR_8660 0x3620 | |
15 | /* CONFIG_ADDR bitmasks */ | |
16 | #define CONFIG 0x9b | |
17 | #define CONFIG_MASK 0xf | |
18 | #define CONFIG_8660 1 | |
19 | #define CONFIG_SHIFT_8660 28 | |
20 | #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) | |
21 | ||
20d4fd84 RN |
22 | #define CNTL_ADDR 0x3620 |
23 | /* CNTL_ADDR bitmasks */ | |
24 | #define EN BIT(0) | |
25 | #define SW_RST BIT(1) | |
2ebd0982 | 26 | |
3d08f029 | 27 | #define MEASURE_PERIOD BIT(18) |
20d4fd84 RN |
28 | #define SLP_CLK_ENA BIT(26) |
29 | #define SLP_CLK_ENA_8660 BIT(24) | |
20d4fd84 RN |
30 | #define SENSOR0_SHIFT 3 |
31 | ||
20d4fd84 | 32 | #define THRESHOLD_ADDR 0x3624 |
20d4fd84 | 33 | |
20d4fd84 | 34 | #define INT_STATUS_ADDR 0x363c |
20d4fd84 | 35 | |
a0ed1411 AS |
36 | #define S0_STATUS_OFF 0x3628 |
37 | #define S1_STATUS_OFF 0x362c | |
38 | #define S2_STATUS_OFF 0x3630 | |
39 | #define S3_STATUS_OFF 0x3634 | |
40 | #define S4_STATUS_OFF 0x3638 | |
41 | #define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ | |
42 | #define S6_STATUS_OFF 0x3668 | |
43 | #define S7_STATUS_OFF 0x366c | |
44 | #define S8_STATUS_OFF 0x3670 | |
45 | #define S9_STATUS_OFF 0x3674 | |
46 | #define S10_STATUS_OFF 0x3678 | |
47 | ||
dfc1193d AS |
48 | /* Original slope - 350 to compensate mC to C inaccuracy */ |
49 | static u32 tsens_msm8960_slope[] = { | |
50 | 826, 826, 804, 826, | |
51 | 761, 782, 782, 849, | |
52 | 782, 849, 782 | |
53 | }; | |
54 | ||
69b628ac | 55 | static int suspend_8960(struct tsens_priv *priv) |
20d4fd84 RN |
56 | { |
57 | int ret; | |
58 | unsigned int mask; | |
69b628ac | 59 | struct regmap *map = priv->tm_map; |
20d4fd84 | 60 | |
69b628ac | 61 | ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); |
20d4fd84 RN |
62 | if (ret) |
63 | return ret; | |
64 | ||
69b628ac | 65 | ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); |
20d4fd84 RN |
66 | if (ret) |
67 | return ret; | |
68 | ||
69b628ac | 69 | if (priv->num_sensors > 1) |
20d4fd84 RN |
70 | mask = SLP_CLK_ENA | EN; |
71 | else | |
72 | mask = SLP_CLK_ENA_8660 | EN; | |
73 | ||
74 | ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); | |
75 | if (ret) | |
76 | return ret; | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
69b628ac | 81 | static int resume_8960(struct tsens_priv *priv) |
20d4fd84 RN |
82 | { |
83 | int ret; | |
69b628ac | 84 | struct regmap *map = priv->tm_map; |
20d4fd84 RN |
85 | |
86 | ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); | |
87 | if (ret) | |
88 | return ret; | |
89 | ||
90 | /* | |
91 | * Separate CONFIG restore is not needed only for 8660 as | |
92 | * config is part of CTRL Addr and its restored as such | |
93 | */ | |
69b628ac | 94 | if (priv->num_sensors > 1) { |
20d4fd84 RN |
95 | ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); |
96 | if (ret) | |
97 | return ret; | |
98 | } | |
99 | ||
69b628ac | 100 | ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); |
20d4fd84 RN |
101 | if (ret) |
102 | return ret; | |
103 | ||
69b628ac | 104 | ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); |
20d4fd84 RN |
105 | if (ret) |
106 | return ret; | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
69b628ac | 111 | static int enable_8960(struct tsens_priv *priv, int id) |
20d4fd84 RN |
112 | { |
113 | int ret; | |
3d08f029 | 114 | u32 reg, mask = BIT(id); |
20d4fd84 | 115 | |
69b628ac | 116 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); |
20d4fd84 RN |
117 | if (ret) |
118 | return ret; | |
119 | ||
3d08f029 AS |
120 | /* HARDWARE BUG: |
121 | * On platforms with more than 6 sensors, all remaining sensors | |
122 | * must be enabled together, otherwise undefined results are expected. | |
123 | * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, | |
124 | * all the sensors are enabled in one step hence this bug is not | |
125 | * triggered. | |
126 | */ | |
127 | if (id > 5) | |
128 | mask = GENMASK(10, 6); | |
129 | ||
130 | mask <<= SENSOR0_SHIFT; | |
131 | ||
132 | /* Sensors already enabled. Skip. */ | |
133 | if ((reg & mask) == mask) | |
134 | return 0; | |
135 | ||
69b628ac | 136 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); |
20d4fd84 RN |
137 | if (ret) |
138 | return ret; | |
139 | ||
3d08f029 AS |
140 | reg |= MEASURE_PERIOD; |
141 | ||
69b628ac | 142 | if (priv->num_sensors > 1) |
20d4fd84 RN |
143 | reg |= mask | SLP_CLK_ENA | EN; |
144 | else | |
145 | reg |= mask | SLP_CLK_ENA_8660 | EN; | |
146 | ||
69b628ac | 147 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg); |
20d4fd84 RN |
148 | if (ret) |
149 | return ret; | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
69b628ac | 154 | static void disable_8960(struct tsens_priv *priv) |
20d4fd84 RN |
155 | { |
156 | int ret; | |
157 | u32 reg_cntl; | |
158 | u32 mask; | |
159 | ||
69b628ac | 160 | mask = GENMASK(priv->num_sensors - 1, 0); |
20d4fd84 RN |
161 | mask <<= SENSOR0_SHIFT; |
162 | mask |= EN; | |
163 | ||
69b628ac | 164 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); |
20d4fd84 RN |
165 | if (ret) |
166 | return; | |
167 | ||
168 | reg_cntl &= ~mask; | |
169 | ||
69b628ac | 170 | if (priv->num_sensors > 1) |
20d4fd84 RN |
171 | reg_cntl &= ~SLP_CLK_ENA; |
172 | else | |
173 | reg_cntl &= ~SLP_CLK_ENA_8660; | |
174 | ||
69b628ac | 175 | regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); |
20d4fd84 RN |
176 | } |
177 | ||
69b628ac | 178 | static int calibrate_8960(struct tsens_priv *priv) |
20d4fd84 RN |
179 | { |
180 | int i; | |
181 | char *data; | |
dfc1193d | 182 | u32 p1[11]; |
20d4fd84 | 183 | |
69b628ac | 184 | data = qfprom_read(priv->dev, "calib"); |
20d4fd84 | 185 | if (IS_ERR(data)) |
69b628ac | 186 | data = qfprom_read(priv->dev, "calib_backup"); |
20d4fd84 RN |
187 | if (IS_ERR(data)) |
188 | return PTR_ERR(data); | |
189 | ||
dfc1193d AS |
190 | for (i = 0; i < priv->num_sensors; i++) { |
191 | p1[i] = data[i]; | |
192 | priv->sensor[i].slope = tsens_msm8960_slope[i]; | |
193 | } | |
194 | ||
195 | compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); | |
20d4fd84 | 196 | |
6b8249ab SK |
197 | kfree(data); |
198 | ||
20d4fd84 RN |
199 | return 0; |
200 | } | |
201 | ||
a0ed1411 AS |
202 | static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { |
203 | /* ----- SROT ------ */ | |
204 | /* No VERSION information */ | |
205 | ||
206 | /* CNTL */ | |
207 | [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), | |
208 | [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), | |
209 | /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ | |
210 | [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), | |
211 | ||
212 | /* ----- TM ------ */ | |
213 | /* INTERRUPT ENABLE */ | |
214 | /* NO INTERRUPT ENABLE */ | |
215 | ||
216 | /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ | |
217 | [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), | |
218 | [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), | |
219 | /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield | |
220 | * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp | |
221 | * MIN_THRESH_0 -> CRIT_THRESH_1 | |
222 | * MAX_THRESH_0 -> CRIT_THRESH_0 | |
223 | */ | |
224 | [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), | |
225 | [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), | |
226 | ||
227 | /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ | |
228 | /* 1 == clear, 0 == normal operation */ | |
229 | [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), | |
230 | [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), | |
231 | ||
232 | /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ | |
233 | ||
234 | /* Sn_STATUS */ | |
235 | [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), | |
236 | [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), | |
237 | [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), | |
238 | [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), | |
239 | [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), | |
240 | [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), | |
241 | [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), | |
242 | [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), | |
243 | [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), | |
244 | [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), | |
245 | [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), | |
246 | ||
247 | /* No VALID field on 8960 */ | |
248 | /* TSENS_INT_STATUS bits: 1 == threshold violated */ | |
249 | [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), | |
250 | [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), | |
251 | [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), | |
252 | /* No CRITICAL field on 8960 */ | |
253 | [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), | |
254 | ||
255 | /* TRDY: 1=ready, 0=in progress */ | |
256 | [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), | |
257 | }; | |
258 | ||
032d4057 | 259 | static const struct tsens_ops ops_8960 = { |
fdda131f | 260 | .init = init_common, |
20d4fd84 | 261 | .calibrate = calibrate_8960, |
dfc1193d | 262 | .get_temp = get_temp_common, |
20d4fd84 RN |
263 | .enable = enable_8960, |
264 | .disable = disable_8960, | |
265 | .suspend = suspend_8960, | |
266 | .resume = resume_8960, | |
267 | }; | |
268 | ||
53e2a20e AS |
269 | static struct tsens_features tsens_8960_feat = { |
270 | .ver_major = VER_0, | |
271 | .crit_int = 0, | |
4360af35 | 272 | .combo_int = 0, |
53e2a20e AS |
273 | .adc = 1, |
274 | .srot_split = 0, | |
275 | .max_sensors = 11, | |
f63baced RM |
276 | .trip_min_temp = -40000, |
277 | .trip_max_temp = 120000, | |
53e2a20e AS |
278 | }; |
279 | ||
0aef1ee5 | 280 | struct tsens_plat_data data_8960 = { |
20d4fd84 RN |
281 | .num_sensors = 11, |
282 | .ops = &ops_8960, | |
53e2a20e | 283 | .feat = &tsens_8960_feat, |
a0ed1411 | 284 | .fields = tsens_8960_regfields, |
20d4fd84 | 285 | }; |