Amit Kucheria | 2d71d8d | 2018-09-12 15:22:47 +0530 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 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 | |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 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 | |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 22 | #define CNTL_ADDR 0x3620 |
| 23 | /* CNTL_ADDR bitmasks */ |
| 24 | #define EN BIT(0) |
| 25 | #define SW_RST BIT(1) |
Ansuel Smith | 2ebd098 | 2021-04-20 20:33:41 +0200 | [diff] [blame] | 26 | |
Ansuel Smith | 3d08f02 | 2021-04-20 20:33:39 +0200 | [diff] [blame] | 27 | #define MEASURE_PERIOD BIT(18) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 28 | #define SLP_CLK_ENA BIT(26) |
| 29 | #define SLP_CLK_ENA_8660 BIT(24) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 30 | #define SENSOR0_SHIFT 3 |
| 31 | |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 32 | #define THRESHOLD_ADDR 0x3624 |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 33 | |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 34 | #define INT_STATUS_ADDR 0x363c |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 35 | |
Ansuel Smith | a0ed141 | 2021-04-20 20:33:36 +0200 | [diff] [blame] | 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 | |
Ansuel Smith | dfc1193 | 2021-04-20 20:33:40 +0200 | [diff] [blame] | 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 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 55 | static int suspend_8960(struct tsens_priv *priv) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 56 | { |
| 57 | int ret; |
| 58 | unsigned int mask; |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 59 | struct regmap *map = priv->tm_map; |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 60 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 61 | ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 62 | if (ret) |
| 63 | return ret; |
| 64 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 65 | ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 66 | if (ret) |
| 67 | return ret; |
| 68 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 69 | if (priv->num_sensors > 1) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 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 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 81 | static int resume_8960(struct tsens_priv *priv) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 82 | { |
| 83 | int ret; |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 84 | struct regmap *map = priv->tm_map; |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 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 | */ |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 94 | if (priv->num_sensors > 1) { |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 95 | ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); |
| 96 | if (ret) |
| 97 | return ret; |
| 98 | } |
| 99 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 100 | ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 101 | if (ret) |
| 102 | return ret; |
| 103 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 104 | ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 105 | if (ret) |
| 106 | return ret; |
| 107 | |
| 108 | return 0; |
| 109 | } |
| 110 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 111 | static int enable_8960(struct tsens_priv *priv, int id) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 112 | { |
| 113 | int ret; |
Ansuel Smith | 3d08f02 | 2021-04-20 20:33:39 +0200 | [diff] [blame] | 114 | u32 reg, mask = BIT(id); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 115 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 116 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 117 | if (ret) |
| 118 | return ret; |
| 119 | |
Ansuel Smith | 3d08f02 | 2021-04-20 20:33:39 +0200 | [diff] [blame] | 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 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 136 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 137 | if (ret) |
| 138 | return ret; |
| 139 | |
Ansuel Smith | 3d08f02 | 2021-04-20 20:33:39 +0200 | [diff] [blame] | 140 | reg |= MEASURE_PERIOD; |
| 141 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 142 | if (priv->num_sensors > 1) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 143 | reg |= mask | SLP_CLK_ENA | EN; |
| 144 | else |
| 145 | reg |= mask | SLP_CLK_ENA_8660 | EN; |
| 146 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 147 | ret = regmap_write(priv->tm_map, CNTL_ADDR, reg); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 148 | if (ret) |
| 149 | return ret; |
| 150 | |
| 151 | return 0; |
| 152 | } |
| 153 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 154 | static void disable_8960(struct tsens_priv *priv) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 155 | { |
| 156 | int ret; |
| 157 | u32 reg_cntl; |
| 158 | u32 mask; |
| 159 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 160 | mask = GENMASK(priv->num_sensors - 1, 0); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 161 | mask <<= SENSOR0_SHIFT; |
| 162 | mask |= EN; |
| 163 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 164 | ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 165 | if (ret) |
| 166 | return; |
| 167 | |
| 168 | reg_cntl &= ~mask; |
| 169 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 170 | if (priv->num_sensors > 1) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 171 | reg_cntl &= ~SLP_CLK_ENA; |
| 172 | else |
| 173 | reg_cntl &= ~SLP_CLK_ENA_8660; |
| 174 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 175 | regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 176 | } |
| 177 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 178 | static int calibrate_8960(struct tsens_priv *priv) |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 179 | { |
| 180 | int i; |
| 181 | char *data; |
Ansuel Smith | dfc1193 | 2021-04-20 20:33:40 +0200 | [diff] [blame] | 182 | u32 p1[11]; |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 183 | |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 184 | data = qfprom_read(priv->dev, "calib"); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 185 | if (IS_ERR(data)) |
Amit Kucheria | 69b628a | 2019-03-20 18:47:44 +0530 | [diff] [blame] | 186 | data = qfprom_read(priv->dev, "calib_backup"); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 187 | if (IS_ERR(data)) |
| 188 | return PTR_ERR(data); |
| 189 | |
Ansuel Smith | dfc1193 | 2021-04-20 20:33:40 +0200 | [diff] [blame] | 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); |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 196 | |
Srinivas Kandagatla | 6b8249a | 2019-08-23 10:38:35 +0100 | [diff] [blame] | 197 | kfree(data); |
| 198 | |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 199 | return 0; |
| 200 | } |
| 201 | |
Ansuel Smith | a0ed141 | 2021-04-20 20:33:36 +0200 | [diff] [blame] | 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 | |
Eduardo Valentin | 032d405 | 2016-07-01 18:02:09 -0700 | [diff] [blame] | 259 | static const struct tsens_ops ops_8960 = { |
Ansuel Smith | fdda131 | 2021-04-20 20:33:38 +0200 | [diff] [blame] | 260 | .init = init_common, |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 261 | .calibrate = calibrate_8960, |
Ansuel Smith | dfc1193 | 2021-04-20 20:33:40 +0200 | [diff] [blame] | 262 | .get_temp = get_temp_common, |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 263 | .enable = enable_8960, |
| 264 | .disable = disable_8960, |
| 265 | .suspend = suspend_8960, |
| 266 | .resume = resume_8960, |
| 267 | }; |
| 268 | |
Ansuel Smith | 53e2a20 | 2021-04-20 20:33:37 +0200 | [diff] [blame] | 269 | static struct tsens_features tsens_8960_feat = { |
| 270 | .ver_major = VER_0, |
| 271 | .crit_int = 0, |
| 272 | .adc = 1, |
| 273 | .srot_split = 0, |
| 274 | .max_sensors = 11, |
| 275 | }; |
| 276 | |
Amit Kucheria | 0aef1ee | 2020-03-12 18:06:58 +0530 | [diff] [blame] | 277 | struct tsens_plat_data data_8960 = { |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 278 | .num_sensors = 11, |
| 279 | .ops = &ops_8960, |
Ansuel Smith | 53e2a20 | 2021-04-20 20:33:37 +0200 | [diff] [blame] | 280 | .feat = &tsens_8960_feat, |
Ansuel Smith | a0ed141 | 2021-04-20 20:33:36 +0200 | [diff] [blame] | 281 | .fields = tsens_8960_regfields, |
Rajendra Nayak | 20d4fd8 | 2016-05-05 14:21:43 +0530 | [diff] [blame] | 282 | }; |