tsens-8960.c (6884B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2015, The Linux Foundation. All rights reserved. 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 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 22#define CNTL_ADDR 0x3620 23/* CNTL_ADDR bitmasks */ 24#define EN BIT(0) 25#define SW_RST BIT(1) 26 27#define MEASURE_PERIOD BIT(18) 28#define SLP_CLK_ENA BIT(26) 29#define SLP_CLK_ENA_8660 BIT(24) 30#define SENSOR0_SHIFT 3 31 32#define THRESHOLD_ADDR 0x3624 33 34#define INT_STATUS_ADDR 0x363c 35 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 48/* Original slope - 350 to compensate mC to C inaccuracy */ 49static u32 tsens_msm8960_slope[] = { 50 826, 826, 804, 826, 51 761, 782, 782, 849, 52 782, 849, 782 53 }; 54 55static int suspend_8960(struct tsens_priv *priv) 56{ 57 int ret; 58 unsigned int mask; 59 struct regmap *map = priv->tm_map; 60 61 ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); 62 if (ret) 63 return ret; 64 65 ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); 66 if (ret) 67 return ret; 68 69 if (priv->num_sensors > 1) 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 81static int resume_8960(struct tsens_priv *priv) 82{ 83 int ret; 84 struct regmap *map = priv->tm_map; 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 */ 94 if (priv->num_sensors > 1) { 95 ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); 96 if (ret) 97 return ret; 98 } 99 100 ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); 101 if (ret) 102 return ret; 103 104 ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); 105 if (ret) 106 return ret; 107 108 return 0; 109} 110 111static int enable_8960(struct tsens_priv *priv, int id) 112{ 113 int ret; 114 u32 reg, mask = BIT(id); 115 116 ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); 117 if (ret) 118 return ret; 119 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 136 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); 137 if (ret) 138 return ret; 139 140 reg |= MEASURE_PERIOD; 141 142 if (priv->num_sensors > 1) 143 reg |= mask | SLP_CLK_ENA | EN; 144 else 145 reg |= mask | SLP_CLK_ENA_8660 | EN; 146 147 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg); 148 if (ret) 149 return ret; 150 151 return 0; 152} 153 154static void disable_8960(struct tsens_priv *priv) 155{ 156 int ret; 157 u32 reg_cntl; 158 u32 mask; 159 160 mask = GENMASK(priv->num_sensors - 1, 0); 161 mask <<= SENSOR0_SHIFT; 162 mask |= EN; 163 164 ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); 165 if (ret) 166 return; 167 168 reg_cntl &= ~mask; 169 170 if (priv->num_sensors > 1) 171 reg_cntl &= ~SLP_CLK_ENA; 172 else 173 reg_cntl &= ~SLP_CLK_ENA_8660; 174 175 regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); 176} 177 178static int calibrate_8960(struct tsens_priv *priv) 179{ 180 int i; 181 char *data; 182 u32 p1[11]; 183 184 data = qfprom_read(priv->dev, "calib"); 185 if (IS_ERR(data)) 186 data = qfprom_read(priv->dev, "calib_backup"); 187 if (IS_ERR(data)) 188 return PTR_ERR(data); 189 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); 196 197 kfree(data); 198 199 return 0; 200} 201 202static 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 259static const struct tsens_ops ops_8960 = { 260 .init = init_common, 261 .calibrate = calibrate_8960, 262 .get_temp = get_temp_common, 263 .enable = enable_8960, 264 .disable = disable_8960, 265 .suspend = suspend_8960, 266 .resume = resume_8960, 267}; 268 269static 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 277struct tsens_plat_data data_8960 = { 278 .num_sensors = 11, 279 .ops = &ops_8960, 280 .feat = &tsens_8960_feat, 281 .fields = tsens_8960_regfields, 282};